if.c revision 190712
118316Swollman/* 218316Swollman * Copyright (c) 1983, 1993 318316Swollman * The Regents of the University of California. All rights reserved. 418316Swollman * 518316Swollman * Redistribution and use in source and binary forms, with or without 618316Swollman * modification, are permitted provided that the following conditions 718316Swollman * are met: 818316Swollman * 1. Redistributions of source code must retain the above copyright 918316Swollman * notice, this list of conditions and the following disclaimer. 1018316Swollman * 2. Redistributions in binary form must reproduce the above copyright 1118316Swollman * notice, this list of conditions and the following disclaimer in the 1218316Swollman * documentation and/or other materials provided with the distribution. 1318316Swollman * 4. Neither the name of the University nor the names of its contributors 1418316Swollman * may be used to endorse or promote products derived from this software 1518316Swollman * without specific prior written permission. 1618316Swollman * 1718316Swollman * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 1818316Swollman * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1918316Swollman * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2018316Swollman * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2118316Swollman * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2218316Swollman * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2318316Swollman * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2418316Swollman * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2518316Swollman * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2618316Swollman * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2718316Swollman * SUCH DAMAGE. 2846303Smarkm * 2950476Speter * $FreeBSD: head/sbin/routed/if.c 190712 2009-04-05 14:15:05Z phk $ 3018316Swollman */ 3118316Swollman 3218316Swollman#include "defs.h" 3318316Swollman#include "pathnames.h" 3418316Swollman 35126250Sbms#ifdef __NetBSD__ 3646303Smarkm__RCSID("$NetBSD$"); 37126250Sbms#elif defined(__FreeBSD__) 38126250Sbms__RCSID("$FreeBSD: head/sbin/routed/if.c 190712 2009-04-05 14:15:05Z phk $"); 39126250Sbms#else 40126250Sbms__RCSID("$Revision: 2.27 $"); 41126250Sbms#ident "$Revision: 2.27 $" 4246303Smarkm#endif 43146838Sstefanf 44190711Sphkstruct ifhead ifnet = LIST_HEAD_INITIALIZER(ifnet); /* all interfaces */ 4519880Swollman 4619880Swollman/* hash table for all interfaces, big enough to tolerate ridiculous 4719880Swollman * numbers of IP aliases. Crazy numbers of aliases such as 7000 4819880Swollman * still will not do well, but not just in looking up interfaces 4919880Swollman * by name or address. 5019880Swollman */ 5119880Swollman#define AHASH_LEN 211 /* must be prime */ 5221378Swollman#define AHASH(a) &ahash_tbl[(a)%AHASH_LEN] 5321378Swollmanstruct interface *ahash_tbl[AHASH_LEN]; 5419880Swollman 5519880Swollman#define BHASH_LEN 211 /* must be prime */ 5621378Swollman#define BHASH(a) &bhash_tbl[(a)%BHASH_LEN] 5721378Swollmanstruct interface *bhash_tbl[BHASH_LEN]; 5819880Swollman 5919880Swollmanstruct interface *remote_if; /* remote interfaces */ 6019880Swollman 6119880Swollman/* hash for physical interface names. 6219880Swollman * Assume there are never more 100 or 200 real interfaces, and that 6320606Swollman * aliases are put on the end of the hash chains. 6419880Swollman */ 6519880Swollman#define NHASH_LEN 97 6621378Swollmanstruct interface *nhash_tbl[NHASH_LEN]; 6719880Swollman 6818316Swollmanint tot_interfaces; /* # of remote and local interfaces */ 6918316Swollmanint rip_interfaces; /* # of interfaces doing RIP */ 7018316Swollmanint foundloopback; /* valid flag for loopaddr */ 7118316Swollmannaddr loopaddr; /* our address on loopback */ 7246303Smarkmstruct rt_spare loop_rts; 7318316Swollman 7418316Swollmanstruct timeval ifinit_timer; 7520606Swollmanstatic struct timeval last_ifinit; 7646303Smarkm#define IF_RESCAN_DELAY() (last_ifinit.tv_sec == now.tv_sec \ 7746303Smarkm && last_ifinit.tv_usec == now.tv_usec \ 7846303Smarkm && timercmp(&ifinit_timer, &now, >)) 7918316Swollman 8018316Swollmanint have_ripv1_out; /* have a RIPv1 interface */ 8118316Swollmanint have_ripv1_in; 8218316Swollman 8318316Swollman 8421378Swollmanstatic struct interface** 8546303Smarkmnhash(char *p) 8621378Swollman{ 8746303Smarkm u_int i; 8821378Swollman 8921378Swollman for (i = 0; *p != '\0'; p++) { 9021378Swollman i = ((i<<1) & 0x7fffffff) | ((i>>31) & 1); 9121378Swollman i ^= *p; 9221378Swollman } 9321378Swollman return &nhash_tbl[i % NHASH_LEN]; 9421378Swollman} 9521378Swollman 9621378Swollman 9720606Swollman/* Link a new interface into the lists and hash tables. 9820606Swollman */ 9919880Swollmanvoid 10019880Swollmanif_link(struct interface *ifp) 10119880Swollman{ 10219880Swollman struct interface **hifp; 10319880Swollman 104190711Sphk LIST_INSERT_HEAD(&ifnet, ifp, int_list); 10519880Swollman 10619880Swollman hifp = AHASH(ifp->int_addr); 10719880Swollman ifp->int_ahash_prev = hifp; 10819880Swollman if ((ifp->int_ahash = *hifp) != 0) 10919880Swollman (*hifp)->int_ahash_prev = &ifp->int_ahash; 11019880Swollman *hifp = ifp; 11119880Swollman 11219880Swollman if (ifp->int_if_flags & IFF_BROADCAST) { 11319880Swollman hifp = BHASH(ifp->int_brdaddr); 11419880Swollman ifp->int_bhash_prev = hifp; 11519880Swollman if ((ifp->int_bhash = *hifp) != 0) 11619880Swollman (*hifp)->int_bhash_prev = &ifp->int_bhash; 11719880Swollman *hifp = ifp; 11819880Swollman } 11919880Swollman 12019880Swollman if (ifp->int_state & IS_REMOTE) { 12119880Swollman ifp->int_rlink_prev = &remote_if; 12219880Swollman ifp->int_rlink = remote_if; 12319880Swollman if (remote_if != 0) 12419880Swollman remote_if->int_rlink_prev = &ifp->int_rlink; 12519880Swollman remote_if = ifp; 12619880Swollman } 12719880Swollman 12821378Swollman hifp = nhash(ifp->int_name); 12919880Swollman if (ifp->int_state & IS_ALIAS) { 13020606Swollman /* put aliases on the end of the hash chain */ 13119880Swollman while (*hifp != 0) 13219880Swollman hifp = &(*hifp)->int_nhash; 13319880Swollman } 13419880Swollman ifp->int_nhash_prev = hifp; 13519880Swollman if ((ifp->int_nhash = *hifp) != 0) 13619880Swollman (*hifp)->int_nhash_prev = &ifp->int_nhash; 13719880Swollman *hifp = ifp; 13819880Swollman} 13919880Swollman 14019880Swollman 14118316Swollman/* Find the interface with an address 14218316Swollman */ 14318316Swollmanstruct interface * 14418316Swollmanifwithaddr(naddr addr, 14518316Swollman int bcast, /* notice IFF_BROADCAST address */ 14618316Swollman int remote) /* include IS_REMOTE interfaces */ 14718316Swollman{ 14818316Swollman struct interface *ifp, *possible = 0; 14918316Swollman 15019880Swollman remote = (remote == 0) ? IS_REMOTE : 0; 15118316Swollman 15219880Swollman for (ifp = *AHASH(addr); ifp; ifp = ifp->int_ahash) { 15319880Swollman if (ifp->int_addr != addr) 15419880Swollman continue; 15519880Swollman if ((ifp->int_state & remote) != 0) 15619880Swollman continue; 15719880Swollman if ((ifp->int_state & (IS_BROKE | IS_PASSIVE)) == 0) 15819880Swollman return ifp; 15919880Swollman possible = ifp; 16019880Swollman } 16118316Swollman 16219880Swollman if (possible || !bcast) 16319880Swollman return possible; 16419880Swollman 16519880Swollman for (ifp = *BHASH(addr); ifp; ifp = ifp->int_bhash) { 16619880Swollman if (ifp->int_brdaddr != addr) 16719880Swollman continue; 16819880Swollman if ((ifp->int_state & remote) != 0) 16919880Swollman continue; 17019880Swollman if ((ifp->int_state & (IS_BROKE | IS_PASSIVE)) == 0) 17119880Swollman return ifp; 17219880Swollman possible = ifp; 17318316Swollman } 17418316Swollman 17518316Swollman return possible; 17618316Swollman} 17718316Swollman 17818316Swollman 17918316Swollman/* find the interface with a name 18018316Swollman */ 18118316Swollmanstruct interface * 18218316Swollmanifwithname(char *name, /* "ec0" or whatever */ 18318316Swollman naddr addr) /* 0 or network address */ 18418316Swollman{ 18518316Swollman struct interface *ifp; 18618316Swollman 18720606Swollman for (;;) { 18821378Swollman for (ifp = *nhash(name); ifp != 0; ifp = ifp->int_nhash) { 18920606Swollman /* If the network address is not specified, 19020606Swollman * ignore any alias interfaces. Otherwise, look 19120606Swollman * for the interface with the target name and address. 19220606Swollman */ 19320606Swollman if (!strcmp(ifp->int_name, name) 19420606Swollman && ((addr == 0 && !(ifp->int_state & IS_ALIAS)) 19520606Swollman || (ifp->int_addr == addr))) 19620606Swollman return ifp; 19720606Swollman } 19820606Swollman 19920606Swollman /* If there is no known interface, maybe there is a 20020606Swollman * new interface. So just once look for new interfaces. 20119880Swollman */ 20246303Smarkm if (IF_RESCAN_DELAY()) 20320606Swollman return 0; 20420606Swollman ifinit(); 20518316Swollman } 20618316Swollman} 20718316Swollman 20818316Swollman 20918316Swollmanstruct interface * 210126250Sbmsifwithindex(u_short ifindex, 21146303Smarkm int rescan_ok) 21218316Swollman{ 21318316Swollman struct interface *ifp; 21418316Swollman 21546303Smarkm for (;;) { 216190711Sphk LIST_FOREACH(ifp, &ifnet, int_list) { 217126250Sbms if (ifp->int_index == ifindex) 21846303Smarkm return ifp; 21946303Smarkm } 22018316Swollman 22146303Smarkm /* If there is no known interface, maybe there is a 22246303Smarkm * new interface. So just once look for new interfaces. 22346303Smarkm */ 22446303Smarkm if (!rescan_ok 22546303Smarkm || IF_RESCAN_DELAY()) 22646303Smarkm return 0; 22746303Smarkm ifinit(); 22818316Swollman } 22918316Swollman} 23018316Swollman 23118316Swollman 23218316Swollman/* Find an interface from which the specified address 23318316Swollman * should have come from. Used for figuring out which 23420339Swollman * interface a packet came in on. 23518316Swollman */ 23618316Swollmanstruct interface * 23718316Swollmaniflookup(naddr addr) 23818316Swollman{ 23918316Swollman struct interface *ifp, *maybe; 240126250Sbms int once = 0; 24118316Swollman 24218316Swollman maybe = 0; 24320339Swollman for (;;) { 244190711Sphk LIST_FOREACH(ifp, &ifnet, int_list) { 24520339Swollman if (ifp->int_if_flags & IFF_POINTOPOINT) { 24620339Swollman /* finished with a match */ 24720339Swollman if (ifp->int_dstaddr == addr) 24820339Swollman return ifp; 24918316Swollman 25020339Swollman } else { 25120339Swollman /* finished with an exact match */ 25220339Swollman if (ifp->int_addr == addr) 25320339Swollman return ifp; 25418316Swollman 25520339Swollman /* Look for the longest approximate match. 25620339Swollman */ 25720339Swollman if (on_net(addr, ifp->int_net, ifp->int_mask) 25820339Swollman && (maybe == 0 25920339Swollman || ifp->int_mask > maybe->int_mask)) 26020339Swollman maybe = ifp; 26120339Swollman } 26218316Swollman } 26320339Swollman 264126250Sbms if (maybe != 0 || once || IF_RESCAN_DELAY()) 26520339Swollman return maybe; 266126250Sbms once = 1; 26720339Swollman 26820339Swollman /* If there is no known interface, maybe there is a 26920339Swollman * new interface. So just once look for new interfaces. 27020339Swollman */ 27120339Swollman ifinit(); 27218316Swollman } 27318316Swollman} 27418316Swollman 27518316Swollman 27618316Swollman/* Return the classical netmask for an IP address. 27718316Swollman */ 27820339Swollmannaddr /* host byte order */ 27920339Swollmanstd_mask(naddr addr) /* network byte order */ 28018316Swollman{ 28190868Smike addr = ntohl(addr); /* was a host, not a network */ 28218316Swollman 28318316Swollman if (addr == 0) /* default route has mask 0 */ 28418316Swollman return 0; 28518316Swollman if (IN_CLASSA(addr)) 28618316Swollman return IN_CLASSA_NET; 28718316Swollman if (IN_CLASSB(addr)) 28818316Swollman return IN_CLASSB_NET; 28918316Swollman return IN_CLASSC_NET; 29018316Swollman} 29118316Swollman 29218316Swollman 29318316Swollman/* Find the netmask that would be inferred by RIPv1 listeners 29418316Swollman * on the given interface for a given network. 29518316Swollman * If no interface is specified, look for the best fitting interface. 29618316Swollman */ 29718316Swollmannaddr 29818316Swollmanripv1_mask_net(naddr addr, /* in network byte order */ 29918316Swollman struct interface *ifp) /* as seen on this interface */ 30018316Swollman{ 30146303Smarkm struct r1net *r1p; 30218316Swollman naddr mask = 0; 30318316Swollman 30418316Swollman if (addr == 0) /* default always has 0 mask */ 30518316Swollman return mask; 30618316Swollman 30746303Smarkm if (ifp != 0 && ifp->int_ripv1_mask != HOST_MASK) { 30818316Swollman /* If the target network is that of the associated interface 30918316Swollman * on which it arrived, then use the netmask of the interface. 31018316Swollman */ 31118316Swollman if (on_net(addr, ifp->int_net, ifp->int_std_mask)) 31218316Swollman mask = ifp->int_ripv1_mask; 31318316Swollman 31418316Swollman } else { 31518316Swollman /* Examine all interfaces, and if it the target seems 31618316Swollman * to have the same network number of an interface, use the 31718316Swollman * netmask of that interface. If there is more than one 31818316Swollman * such interface, prefer the interface with the longest 31918316Swollman * match. 32018316Swollman */ 321190711Sphk LIST_FOREACH(ifp, &ifnet, int_list) { 32218316Swollman if (on_net(addr, ifp->int_std_net, ifp->int_std_mask) 32346303Smarkm && ifp->int_ripv1_mask > mask 32446303Smarkm && ifp->int_ripv1_mask != HOST_MASK) 32518316Swollman mask = ifp->int_ripv1_mask; 32618316Swollman } 32746303Smarkm 32818316Swollman } 32918316Swollman 33046303Smarkm /* check special definitions */ 33146303Smarkm if (mask == 0) { 33246303Smarkm for (r1p = r1nets; r1p != 0; r1p = r1p->r1net_next) { 33346303Smarkm if (on_net(addr, r1p->r1net_net, r1p->r1net_match) 33446303Smarkm && r1p->r1net_mask > mask) 33546303Smarkm mask = r1p->r1net_mask; 33646303Smarkm } 33718316Swollman 33846303Smarkm /* Otherwise, make the classic A/B/C guess. 33946303Smarkm */ 34046303Smarkm if (mask == 0) 34146303Smarkm mask = std_mask(addr); 34246303Smarkm } 34346303Smarkm 34418316Swollman return mask; 34518316Swollman} 34618316Swollman 34718316Swollman 34818316Swollmannaddr 34918316Swollmanripv1_mask_host(naddr addr, /* in network byte order */ 35018316Swollman struct interface *ifp) /* as seen on this interface */ 35118316Swollman{ 35218316Swollman naddr mask = ripv1_mask_net(addr, ifp); 35318316Swollman 35418316Swollman 35518316Swollman /* If the computed netmask does not mask the address, 35618316Swollman * then assume it is a host address 35718316Swollman */ 35818316Swollman if ((ntohl(addr) & ~mask) != 0) 35918316Swollman mask = HOST_MASK; 36018316Swollman return mask; 36118316Swollman} 36218316Swollman 36318316Swollman 364108533Sschweikh/* See if an IP address looks reasonable as a destination. 36518316Swollman */ 36618316Swollmanint /* 0=bad */ 36718316Swollmancheck_dst(naddr addr) 36818316Swollman{ 36990868Smike addr = ntohl(addr); 37018316Swollman 37118316Swollman if (IN_CLASSA(addr)) { 37218316Swollman if (addr == 0) 37318316Swollman return 1; /* default */ 37418316Swollman 37518316Swollman addr >>= IN_CLASSA_NSHIFT; 37618316Swollman return (addr != 0 && addr != IN_LOOPBACKNET); 37718316Swollman } 37818316Swollman 37918316Swollman return (IN_CLASSB(addr) || IN_CLASSC(addr)); 38018316Swollman} 38118316Swollman 38218316Swollman 38319880Swollman/* See a new interface duplicates an existing interface. 38419880Swollman */ 38519880Swollmanstruct interface * 38620339Swollmancheck_dup(naddr addr, /* IP address, so network byte order */ 38720339Swollman naddr dstaddr, /* ditto */ 38820339Swollman naddr mask, /* mask, so host byte order */ 38919880Swollman int if_flags) 39019880Swollman{ 39119880Swollman struct interface *ifp; 39219880Swollman 393190711Sphk LIST_FOREACH(ifp, &ifnet, int_list) { 39419880Swollman if (ifp->int_mask != mask) 39519880Swollman continue; 39619880Swollman 39746303Smarkm if (!iff_up(ifp->int_if_flags)) 39819880Swollman continue; 39919880Swollman 40046303Smarkm /* The local address can only be shared with a point-to-point 40146303Smarkm * link. 40219880Swollman */ 403126250Sbms if ((!(ifp->int_state & IS_REMOTE) || !(if_flags & IS_REMOTE)) 404126250Sbms && ifp->int_addr == addr 40519880Swollman && (((if_flags|ifp->int_if_flags) & IFF_POINTOPOINT) == 0)) 40619880Swollman return ifp; 40719880Swollman 40819880Swollman if (on_net(ifp->int_dstaddr, ntohl(dstaddr),mask)) 40919880Swollman return ifp; 41019880Swollman } 41119880Swollman return 0; 41219880Swollman} 41319880Swollman 41419880Swollman 41519880Swollman/* See that a remote gateway is reachable. 41619880Swollman * Note that the answer can change as real interfaces come and go. 41719880Swollman */ 41819880Swollmanint /* 0=bad */ 41919880Swollmancheck_remote(struct interface *ifp) 42019880Swollman{ 42119880Swollman struct rt_entry *rt; 42219880Swollman 42319880Swollman /* do not worry about other kinds */ 42419880Swollman if (!(ifp->int_state & IS_REMOTE)) 42519880Swollman return 1; 42619880Swollman 42719880Swollman rt = rtfind(ifp->int_addr); 42819880Swollman if (rt != 0 42919880Swollman && rt->rt_ifp != 0 43019880Swollman &&on_net(ifp->int_addr, 43119880Swollman rt->rt_ifp->int_net, rt->rt_ifp->int_mask)) 43219880Swollman return 1; 43319880Swollman 43419880Swollman /* the gateway cannot be reached directly from one of our 43519880Swollman * interfaces 43619880Swollman */ 43719880Swollman if (!(ifp->int_state & IS_BROKE)) { 43819880Swollman msglog("unreachable gateway %s in "_PATH_GATEWAYS, 43919880Swollman naddr_ntoa(ifp->int_addr)); 44019880Swollman if_bad(ifp); 44119880Swollman } 44219880Swollman return 0; 44319880Swollman} 44419880Swollman 44519880Swollman 44618316Swollman/* Delete an interface. 44718316Swollman */ 44818316Swollmanstatic void 44918316Swollmanifdel(struct interface *ifp) 45018316Swollman{ 45118316Swollman struct interface *ifp1; 45218316Swollman 45318316Swollman 45418316Swollman trace_if("Del", ifp); 45518316Swollman 45618316Swollman ifp->int_state |= IS_BROKE; 45718316Swollman 458190711Sphk LIST_REMOVE(ifp, int_list); 45919880Swollman *ifp->int_ahash_prev = ifp->int_ahash; 46019880Swollman if (ifp->int_ahash != 0) 46119880Swollman ifp->int_ahash->int_ahash_prev = ifp->int_ahash_prev; 46221378Swollman *ifp->int_nhash_prev = ifp->int_nhash; 46321378Swollman if (ifp->int_nhash != 0) 46421378Swollman ifp->int_nhash->int_nhash_prev = ifp->int_nhash_prev; 46519880Swollman if (ifp->int_if_flags & IFF_BROADCAST) { 46619880Swollman *ifp->int_bhash_prev = ifp->int_bhash; 46719880Swollman if (ifp->int_bhash != 0) 46819880Swollman ifp->int_bhash->int_bhash_prev = ifp->int_bhash_prev; 46919880Swollman } 47019880Swollman if (ifp->int_state & IS_REMOTE) { 47119880Swollman *ifp->int_rlink_prev = ifp->int_rlink; 47219880Swollman if (ifp->int_rlink != 0) 47319880Swollman ifp->int_rlink->int_rlink_prev = ifp->int_rlink_prev; 47419880Swollman } 47518316Swollman 47618316Swollman if (!(ifp->int_state & IS_ALIAS)) { 47719880Swollman /* delete aliases when the main interface dies 47818316Swollman */ 479190711Sphk LIST_FOREACH(ifp1, &ifnet, int_list) { 48018316Swollman if (ifp1 != ifp 48118316Swollman && !strcmp(ifp->int_name, ifp1->int_name)) 48218316Swollman ifdel(ifp1); 48318316Swollman } 48418316Swollman 485180993Sphk if ((ifp->int_if_flags & IFF_MULTICAST) && rip_sock >= 0) { 486180993Sphk struct group_req gr; 487180993Sphk struct sockaddr_in *sin; 488180993Sphk 489180993Sphk memset(&gr, 0, sizeof(gr)); 490180993Sphk gr.gr_interface = ifp->int_index; 491180993Sphk sin = (struct sockaddr_in *)&gr.gr_group; 492180993Sphk sin->sin_family = AF_INET; 493180993Sphk#ifdef _HAVE_SIN_LEN 494180993Sphk sin->sin_len = sizeof(struct sockaddr_in); 49518316Swollman#endif 496180993Sphk sin->sin_addr.s_addr = htonl(INADDR_RIP_GROUP); 497180993Sphk if (setsockopt(rip_sock, IPPROTO_IP, MCAST_LEAVE_GROUP, 498180993Sphk &gr, sizeof(gr)) < 0 49918316Swollman && errno != EADDRNOTAVAIL 50018316Swollman && !TRACEACTIONS) 501180993Sphk LOGERR("setsockopt(MCAST_LEAVE_GROUP RIP)"); 50219880Swollman if (rip_sock_mcast == ifp) 50319880Swollman rip_sock_mcast = 0; 50418316Swollman } 50518316Swollman if (ifp->int_rip_sock >= 0) { 50618316Swollman (void)close(ifp->int_rip_sock); 50718316Swollman ifp->int_rip_sock = -1; 50818316Swollman fix_select(); 50918316Swollman } 51018316Swollman 51118316Swollman tot_interfaces--; 51218316Swollman if (!IS_RIP_OFF(ifp->int_state)) 51318316Swollman rip_interfaces--; 51418316Swollman 51518316Swollman /* Zap all routes associated with this interface. 51646303Smarkm * Assume routes just using gateways beyond this interface 51746303Smarkm * will timeout naturally, and have probably already died. 51818316Swollman */ 51918316Swollman (void)rn_walktree(rhead, walk_bad, 0); 52018316Swollman 52118316Swollman set_rdisc_mg(ifp, 0); 52218316Swollman if_bad_rdisc(ifp); 52318316Swollman } 52418316Swollman 52518316Swollman free(ifp); 52618316Swollman} 52718316Swollman 52818316Swollman 52918316Swollman/* Mark an interface ill. 53018316Swollman */ 53118316Swollmanvoid 53218316Swollmanif_sick(struct interface *ifp) 53318316Swollman{ 53418316Swollman if (0 == (ifp->int_state & (IS_SICK | IS_BROKE))) { 53518316Swollman ifp->int_state |= IS_SICK; 53619880Swollman ifp->int_act_time = NEVER; 53718316Swollman trace_if("Chg", ifp); 53818316Swollman 53918316Swollman LIM_SEC(ifinit_timer, now.tv_sec+CHECK_BAD_INTERVAL); 54018316Swollman } 54118316Swollman} 54218316Swollman 54318316Swollman 54418316Swollman/* Mark an interface dead. 54518316Swollman */ 54618316Swollmanvoid 54718316Swollmanif_bad(struct interface *ifp) 54818316Swollman{ 54918316Swollman struct interface *ifp1; 55018316Swollman 55118316Swollman 55218316Swollman if (ifp->int_state & IS_BROKE) 55318316Swollman return; 55418316Swollman 55518316Swollman LIM_SEC(ifinit_timer, now.tv_sec+CHECK_BAD_INTERVAL); 55618316Swollman 55718316Swollman ifp->int_state |= (IS_BROKE | IS_SICK); 55819880Swollman ifp->int_act_time = NEVER; 55919880Swollman ifp->int_query_time = NEVER; 56046303Smarkm ifp->int_data.ts = now.tv_sec; 56118316Swollman 56218316Swollman trace_if("Chg", ifp); 56318316Swollman 56418316Swollman if (!(ifp->int_state & IS_ALIAS)) { 565190711Sphk LIST_FOREACH(ifp1, &ifnet, int_list) { 56618316Swollman if (ifp1 != ifp 56718316Swollman && !strcmp(ifp->int_name, ifp1->int_name)) 56818316Swollman if_bad(ifp1); 56918316Swollman } 57018316Swollman (void)rn_walktree(rhead, walk_bad, 0); 57118316Swollman if_bad_rdisc(ifp); 57218316Swollman } 57318316Swollman} 57418316Swollman 57518316Swollman 57618316Swollman/* Mark an interface alive 57718316Swollman */ 57818316Swollmanint /* 1=it was dead */ 57918316Swollmanif_ok(struct interface *ifp, 58046303Smarkm const char *type) 58118316Swollman{ 58218316Swollman struct interface *ifp1; 58318316Swollman 58418316Swollman 58518316Swollman if (!(ifp->int_state & IS_BROKE)) { 58618316Swollman if (ifp->int_state & IS_SICK) { 58719880Swollman trace_act("%sinterface %s to %s working better", 58818316Swollman type, 58919880Swollman ifp->int_name, naddr_ntoa(ifp->int_dstaddr)); 59018316Swollman ifp->int_state &= ~IS_SICK; 59118316Swollman } 59218316Swollman return 0; 59318316Swollman } 59418316Swollman 59518316Swollman msglog("%sinterface %s to %s restored", 59619880Swollman type, ifp->int_name, naddr_ntoa(ifp->int_dstaddr)); 59718316Swollman ifp->int_state &= ~(IS_BROKE | IS_SICK); 59818316Swollman ifp->int_data.ts = 0; 59918316Swollman 60018316Swollman if (!(ifp->int_state & IS_ALIAS)) { 601190711Sphk LIST_FOREACH(ifp1, &ifnet, int_list) { 60218316Swollman if (ifp1 != ifp 60318316Swollman && !strcmp(ifp->int_name, ifp1->int_name)) 60418316Swollman if_ok(ifp1, type); 60518316Swollman } 60618316Swollman if_ok_rdisc(ifp); 60718316Swollman } 60819880Swollman 60919880Swollman if (ifp->int_state & IS_REMOTE) { 61019880Swollman if (!addrouteforif(ifp)) 61119880Swollman return 0; 61219880Swollman } 61318316Swollman return 1; 61418316Swollman} 61518316Swollman 61618316Swollman 61746303Smarkm/* disassemble routing message 61818316Swollman */ 61918316Swollmanvoid 62018316Swollmanrt_xaddrs(struct rt_addrinfo *info, 62118316Swollman struct sockaddr *sa, 62218316Swollman struct sockaddr *lim, 62318316Swollman int addrs) 62418316Swollman{ 62518316Swollman int i; 62646303Smarkm#ifdef _HAVE_SA_LEN 62746303Smarkm static struct sockaddr sa_zero; 62846303Smarkm#endif 62918316Swollman 63046303Smarkm memset(info, 0, sizeof(*info)); 63118316Swollman info->rti_addrs = addrs; 63218316Swollman for (i = 0; i < RTAX_MAX && sa < lim; i++) { 63318316Swollman if ((addrs & (1 << i)) == 0) 63418316Swollman continue; 63546303Smarkm info->rti_info[i] = (sa->sa_len != 0) ? sa : &sa_zero; 636128186Sluigi sa = (struct sockaddr *)((char*)(sa) + SA_SIZE(sa)); 63718316Swollman } 63818316Swollman} 63918316Swollman 64018316Swollman 64118316Swollman/* Find the network interfaces which have configured themselves. 64218316Swollman * This must be done regularly, if only for extra addresses 64318316Swollman * that come and go on interfaces. 64418316Swollman */ 64518316Swollmanvoid 64618316Swollmanifinit(void) 64718316Swollman{ 64818316Swollman static char *sysctl_buf; 64918316Swollman static size_t sysctl_buf_size = 0; 65018316Swollman uint complaints = 0; 65118316Swollman static u_int prev_complaints = 0; 65218316Swollman# define COMP_NOT_INET 0x001 65319880Swollman# define COMP_NOADDR 0x002 65419880Swollman# define COMP_BADADDR 0x004 65519880Swollman# define COMP_NODST 0x008 65619880Swollman# define COMP_NOBADR 0x010 65719880Swollman# define COMP_NOMASK 0x020 65819880Swollman# define COMP_DUP 0x040 65919880Swollman# define COMP_BAD_METRIC 0x080 66019880Swollman# define COMP_NETMASK 0x100 66118316Swollman 66218316Swollman struct interface ifs, ifs0, *ifp, *ifp1; 66318316Swollman struct rt_entry *rt; 66418316Swollman size_t needed; 66518316Swollman int mib[6]; 66618316Swollman struct if_msghdr *ifm; 66718316Swollman struct ifa_msghdr *ifam, *ifam_lim, *ifam2; 66818316Swollman int in, ierr, out, oerr; 66918316Swollman struct intnet *intnetp; 67018316Swollman struct rt_addrinfo info; 67118316Swollman#ifdef SIOCGIFMETRIC 67218316Swollman struct ifreq ifr; 67318316Swollman#endif 67418316Swollman 67518316Swollman 67620606Swollman last_ifinit = now; 67718316Swollman ifinit_timer.tv_sec = now.tv_sec + (supplier 67818316Swollman ? CHECK_ACT_INTERVAL 67918316Swollman : CHECK_QUIET_INTERVAL); 68018316Swollman 68137908Scharnier /* mark all interfaces so we can get rid of those that disappear */ 682190711Sphk LIST_FOREACH(ifp, &ifnet, int_list) 68318316Swollman ifp->int_state &= ~(IS_CHECKED | IS_DUP); 68418316Swollman 68518316Swollman /* Fetch the interface list, without too many system calls 68618316Swollman * since we do it repeatedly. 68718316Swollman */ 68818316Swollman mib[0] = CTL_NET; 68918316Swollman mib[1] = PF_ROUTE; 69018316Swollman mib[2] = 0; 69118316Swollman mib[3] = AF_INET; 69218316Swollman mib[4] = NET_RT_IFLIST; 69318316Swollman mib[5] = 0; 69418316Swollman for (;;) { 69518316Swollman if ((needed = sysctl_buf_size) != 0) { 69618316Swollman if (sysctl(mib, 6, sysctl_buf,&needed, 0, 0) >= 0) 69718316Swollman break; 69846303Smarkm /* retry if the table grew */ 69918316Swollman if (errno != ENOMEM && errno != EFAULT) 70046303Smarkm BADERR(1, "ifinit: sysctl(RT_IFLIST)"); 70118316Swollman free(sysctl_buf); 70218316Swollman needed = 0; 70318316Swollman } 70418316Swollman if (sysctl(mib, 6, 0, &needed, 0, 0) < 0) 70546303Smarkm BADERR(1,"ifinit: sysctl(RT_IFLIST) estimate"); 70646303Smarkm sysctl_buf = rtmalloc(sysctl_buf_size = needed, 70746303Smarkm "ifinit sysctl"); 70818316Swollman } 70918316Swollman 71018316Swollman ifam_lim = (struct ifa_msghdr *)(sysctl_buf + needed); 71118316Swollman for (ifam = (struct ifa_msghdr *)sysctl_buf; 71218316Swollman ifam < ifam_lim; 71318316Swollman ifam = ifam2) { 71418316Swollman 71518316Swollman ifam2 = (struct ifa_msghdr*)((char*)ifam + ifam->ifam_msglen); 71618316Swollman 717126250Sbms#ifdef RTM_OIFINFO 718126250Sbms if (ifam->ifam_type == RTM_OIFINFO) 719126250Sbms continue; /* just ignore compat message */ 720126250Sbms#endif 72118316Swollman if (ifam->ifam_type == RTM_IFINFO) { 72219880Swollman struct sockaddr_dl *sdl; 72319880Swollman 72418316Swollman ifm = (struct if_msghdr *)ifam; 72518316Swollman /* make prototype structure for the IP aliases 72618316Swollman */ 72746303Smarkm memset(&ifs0, 0, sizeof(ifs0)); 72818316Swollman ifs0.int_rip_sock = -1; 72918316Swollman ifs0.int_index = ifm->ifm_index; 73018316Swollman ifs0.int_if_flags = ifm->ifm_flags; 73118316Swollman ifs0.int_state = IS_CHECKED; 73220339Swollman ifs0.int_query_time = NEVER; 73318316Swollman ifs0.int_act_time = now.tv_sec; 73418316Swollman ifs0.int_data.ts = now.tv_sec; 73518316Swollman ifs0.int_data.ipackets = ifm->ifm_data.ifi_ipackets; 73618316Swollman ifs0.int_data.ierrors = ifm->ifm_data.ifi_ierrors; 73718316Swollman ifs0.int_data.opackets = ifm->ifm_data.ifi_opackets; 73818316Swollman ifs0.int_data.oerrors = ifm->ifm_data.ifi_oerrors; 73918316Swollman#ifdef sgi 74018316Swollman ifs0.int_data.odrops = ifm->ifm_data.ifi_odrops; 74118316Swollman#endif 74218316Swollman sdl = (struct sockaddr_dl *)(ifm + 1); 74318316Swollman sdl->sdl_data[sdl->sdl_nlen] = 0; 74419880Swollman strncpy(ifs0.int_name, sdl->sdl_data, 74519880Swollman MIN(sizeof(ifs0.int_name), sdl->sdl_nlen)); 74618316Swollman continue; 74718316Swollman } 74818316Swollman if (ifam->ifam_type != RTM_NEWADDR) { 74918316Swollman logbad(1,"ifinit: out of sync"); 75018316Swollman continue; 75118316Swollman } 75218316Swollman rt_xaddrs(&info, (struct sockaddr *)(ifam+1), 75318316Swollman (struct sockaddr *)ifam2, 75418316Swollman ifam->ifam_addrs); 75518316Swollman 75619880Swollman /* Prepare for the next address of this interface, which 75719880Swollman * will be an alias. 75819880Swollman * Do not output RIP or Router-Discovery packets via aliases. 75919880Swollman */ 76046303Smarkm memcpy(&ifs, &ifs0, sizeof(ifs)); 76146303Smarkm ifs0.int_state |= (IS_ALIAS | IS_NO_RIP_OUT | IS_NO_RDISC); 76219880Swollman 76318316Swollman if (INFO_IFA(&info) == 0) { 76446303Smarkm if (iff_up(ifs.int_if_flags)) { 76518316Swollman if (!(prev_complaints & COMP_NOADDR)) 76618316Swollman msglog("%s has no address", 76719880Swollman ifs.int_name); 76818316Swollman complaints |= COMP_NOADDR; 76918316Swollman } 77018316Swollman continue; 77118316Swollman } 77218316Swollman if (INFO_IFA(&info)->sa_family != AF_INET) { 77346303Smarkm if (iff_up(ifs.int_if_flags)) { 77418316Swollman if (!(prev_complaints & COMP_NOT_INET)) 77519880Swollman trace_act("%s: not AF_INET", 77619880Swollman ifs.int_name); 77718316Swollman complaints |= COMP_NOT_INET; 77818316Swollman } 77918316Swollman continue; 78018316Swollman } 78118316Swollman 78218316Swollman ifs.int_addr = S_ADDR(INFO_IFA(&info)); 78318316Swollman 78418316Swollman if (ntohl(ifs.int_addr)>>24 == 0 78518316Swollman || ntohl(ifs.int_addr)>>24 == 0xff) { 78646303Smarkm if (iff_up(ifs.int_if_flags)) { 78718316Swollman if (!(prev_complaints & COMP_BADADDR)) 78818316Swollman msglog("%s has a bad address", 78919880Swollman ifs.int_name); 79018316Swollman complaints |= COMP_BADADDR; 79118316Swollman } 79218316Swollman continue; 79318316Swollman } 79418316Swollman 79519880Swollman if (ifs.int_if_flags & IFF_LOOPBACK) { 796133715Sphk ifs.int_state |= IS_NO_RIP | IS_NO_RDISC; 797153558Smaxim if (ifs.int_addr == htonl(INADDR_LOOPBACK)) 798133715Sphk ifs.int_state |= IS_PASSIVE; 79918316Swollman ifs.int_dstaddr = ifs.int_addr; 80019880Swollman ifs.int_mask = HOST_MASK; 80119880Swollman ifs.int_ripv1_mask = HOST_MASK; 80219880Swollman ifs.int_std_mask = std_mask(ifs.int_dstaddr); 80319880Swollman ifs.int_net = ntohl(ifs.int_dstaddr); 80419880Swollman if (!foundloopback) { 80519880Swollman foundloopback = 1; 80619880Swollman loopaddr = ifs.int_addr; 80746303Smarkm loop_rts.rts_gate = loopaddr; 80846303Smarkm loop_rts.rts_router = loopaddr; 80918316Swollman } 81018316Swollman 81118316Swollman } else if (ifs.int_if_flags & IFF_POINTOPOINT) { 81218316Swollman if (INFO_BRD(&info) == 0 81318316Swollman || INFO_BRD(&info)->sa_family != AF_INET) { 81446303Smarkm if (iff_up(ifs.int_if_flags)) { 81518316Swollman if (!(prev_complaints & COMP_NODST)) 81618316Swollman msglog("%s has a bad" 81718316Swollman " destination address", 81819880Swollman ifs.int_name); 81918316Swollman complaints |= COMP_NODST; 82018316Swollman } 82118316Swollman continue; 82218316Swollman } 82318316Swollman ifs.int_dstaddr = S_ADDR(INFO_BRD(&info)); 82418316Swollman if (ntohl(ifs.int_dstaddr)>>24 == 0 82518316Swollman || ntohl(ifs.int_dstaddr)>>24 == 0xff) { 82646303Smarkm if (iff_up(ifs.int_if_flags)) { 82718316Swollman if (!(prev_complaints & COMP_NODST)) 82818316Swollman msglog("%s has a bad" 82918316Swollman " destination address", 83019880Swollman ifs.int_name); 83118316Swollman complaints |= COMP_NODST; 83218316Swollman } 83318316Swollman continue; 83418316Swollman } 83518316Swollman ifs.int_mask = HOST_MASK; 83618316Swollman ifs.int_ripv1_mask = ntohl(S_ADDR(INFO_MASK(&info))); 83719880Swollman ifs.int_std_mask = std_mask(ifs.int_dstaddr); 83818316Swollman ifs.int_net = ntohl(ifs.int_dstaddr); 83918316Swollman 84019880Swollman } else { 84119880Swollman if (INFO_MASK(&info) == 0) { 84246303Smarkm if (iff_up(ifs.int_if_flags)) { 84319880Swollman if (!(prev_complaints & COMP_NOMASK)) 84419880Swollman msglog("%s has no netmask", 84519880Swollman ifs.int_name); 84619880Swollman complaints |= COMP_NOMASK; 84719880Swollman } 84819880Swollman continue; 84919880Swollman } 85018316Swollman ifs.int_dstaddr = ifs.int_addr; 85119880Swollman ifs.int_mask = ntohl(S_ADDR(INFO_MASK(&info))); 85219880Swollman ifs.int_ripv1_mask = ifs.int_mask; 85319880Swollman ifs.int_std_mask = std_mask(ifs.int_addr); 85419880Swollman ifs.int_net = ntohl(ifs.int_addr) & ifs.int_mask; 85519880Swollman if (ifs.int_mask != ifs.int_std_mask) 85619880Swollman ifs.int_state |= IS_SUBNET; 85719880Swollman 85819880Swollman if (ifs.int_if_flags & IFF_BROADCAST) { 85919880Swollman if (INFO_BRD(&info) == 0) { 86046303Smarkm if (iff_up(ifs.int_if_flags)) { 86119880Swollman if (!(prev_complaints 86219880Swollman & COMP_NOBADR)) 86319880Swollman msglog("%s has" 86419880Swollman "no broadcast address", 86519880Swollman ifs.int_name); 86619880Swollman complaints |= COMP_NOBADR; 86719880Swollman } 86819880Swollman continue; 86919880Swollman } 87019880Swollman ifs.int_brdaddr = S_ADDR(INFO_BRD(&info)); 87118316Swollman } 87218316Swollman } 87318316Swollman ifs.int_std_net = ifs.int_net & ifs.int_std_mask; 87418316Swollman ifs.int_std_addr = htonl(ifs.int_std_net); 87518316Swollman 87618316Swollman /* Use a minimum metric of one. Treat the interface metric 87718316Swollman * (default 0) as an increment to the hop count of one. 87818316Swollman * 87918316Swollman * The metric obtained from the routing socket dump of 88018316Swollman * interface addresses is wrong. It is not set by the 88118316Swollman * SIOCSIFMETRIC ioctl. 88218316Swollman */ 88318316Swollman#ifdef SIOCGIFMETRIC 88419880Swollman strncpy(ifr.ifr_name, ifs.int_name, sizeof(ifr.ifr_name)); 88518316Swollman if (ioctl(rt_sock, SIOCGIFMETRIC, &ifr) < 0) { 88618316Swollman DBGERR(1, "ioctl(SIOCGIFMETRIC)"); 88718316Swollman ifs.int_metric = 0; 88818316Swollman } else { 88918316Swollman ifs.int_metric = ifr.ifr_metric; 89018316Swollman } 89118316Swollman#else 89218316Swollman ifs.int_metric = ifam->ifam_metric; 89318316Swollman#endif 89418316Swollman if (ifs.int_metric > HOPCNT_INFINITY) { 89518316Swollman ifs.int_metric = 0; 89618316Swollman if (!(prev_complaints & COMP_BAD_METRIC) 89746303Smarkm && iff_up(ifs.int_if_flags)) { 89818316Swollman complaints |= COMP_BAD_METRIC; 89918316Swollman msglog("%s has a metric of %d", 90019880Swollman ifs.int_name, ifs.int_metric); 90118316Swollman } 90218316Swollman } 90318316Swollman 90418316Swollman /* See if this is a familiar interface. 90518316Swollman * If so, stop worrying about it if it is the same. 90618316Swollman * Start it over if it now is to somewhere else, as happens 90718316Swollman * frequently with PPP and SLIP. 90818316Swollman */ 90919880Swollman ifp = ifwithname(ifs.int_name, ((ifs.int_state & IS_ALIAS) 91019880Swollman ? ifs.int_addr 91119880Swollman : 0)); 91218316Swollman if (ifp != 0) { 91318316Swollman ifp->int_state |= IS_CHECKED; 91418316Swollman 91518316Swollman if (0 != ((ifp->int_if_flags ^ ifs.int_if_flags) 91618316Swollman & (IFF_BROADCAST 91718316Swollman | IFF_LOOPBACK 91818316Swollman | IFF_POINTOPOINT 91918316Swollman | IFF_MULTICAST)) 92018316Swollman || 0 != ((ifp->int_state ^ ifs.int_state) 92118316Swollman & IS_ALIAS) 92218316Swollman || ifp->int_addr != ifs.int_addr 92318316Swollman || ifp->int_brdaddr != ifs.int_brdaddr 92418316Swollman || ifp->int_dstaddr != ifs.int_dstaddr 92518316Swollman || ifp->int_mask != ifs.int_mask 92618316Swollman || ifp->int_metric != ifs.int_metric) { 92718316Swollman /* Forget old information about 92818316Swollman * a changed interface. 92918316Swollman */ 93019880Swollman trace_act("interface %s has changed", 93118316Swollman ifp->int_name); 93218316Swollman ifdel(ifp); 93318316Swollman ifp = 0; 93418316Swollman } 93518316Swollman } 93618316Swollman 93718316Swollman if (ifp != 0) { 93818316Swollman /* The primary representative of an alias worries 93918316Swollman * about how things are working. 94018316Swollman */ 94118316Swollman if (ifp->int_state & IS_ALIAS) 94218316Swollman continue; 94318316Swollman 94418316Swollman /* note interfaces that have been turned off 94518316Swollman */ 94646303Smarkm if (!iff_up(ifs.int_if_flags)) { 94746303Smarkm if (iff_up(ifp->int_if_flags)) { 94818316Swollman msglog("interface %s to %s turned off", 94918316Swollman ifp->int_name, 95019880Swollman naddr_ntoa(ifp->int_dstaddr)); 95118316Swollman if_bad(ifp); 95246303Smarkm ifp->int_if_flags &= ~IFF_UP; 95346303Smarkm } else if (now.tv_sec>(ifp->int_data.ts 95446303Smarkm + CHECK_BAD_INTERVAL)) { 95546303Smarkm trace_act("interface %s has been off" 95646303Smarkm " %ld seconds; forget it", 95746303Smarkm ifp->int_name, 958190712Sphk (long)now.tv_sec- 959190712Sphk ifp->int_data.ts); 96046303Smarkm ifdel(ifp); 96118316Swollman } 96218316Swollman continue; 96318316Swollman } 96418316Swollman /* or that were off and are now ok */ 96546303Smarkm if (!iff_up(ifp->int_if_flags)) { 96646303Smarkm ifp->int_if_flags |= IFF_UP; 96718316Swollman (void)if_ok(ifp, ""); 96818316Swollman } 96918316Swollman 97018316Swollman /* If it has been long enough, 97118316Swollman * see if the interface is broken. 97218316Swollman */ 97318316Swollman if (now.tv_sec < ifp->int_data.ts+CHECK_BAD_INTERVAL) 97418316Swollman continue; 97518316Swollman 97618316Swollman in = ifs.int_data.ipackets - ifp->int_data.ipackets; 97718316Swollman ierr = ifs.int_data.ierrors - ifp->int_data.ierrors; 97818316Swollman out = ifs.int_data.opackets - ifp->int_data.opackets; 97918316Swollman oerr = ifs.int_data.oerrors - ifp->int_data.oerrors; 98018316Swollman#ifdef sgi 98118316Swollman /* Through at least IRIX 6.2, PPP and SLIP 98246303Smarkm * count packets dropped by the filters. 98318316Swollman * But FDDI rings stuck non-operational count 98418316Swollman * dropped packets as they wait for improvement. 98518316Swollman */ 98618316Swollman if (!(ifp->int_if_flags & IFF_POINTOPOINT)) 98718316Swollman oerr += (ifs.int_data.odrops 98818316Swollman - ifp->int_data.odrops); 98918316Swollman#endif 99018316Swollman /* If the interface just awoke, restart the counters. 99118316Swollman */ 99218316Swollman if (ifp->int_data.ts == 0) { 99318316Swollman ifp->int_data = ifs.int_data; 99418316Swollman continue; 99518316Swollman } 99618316Swollman ifp->int_data = ifs.int_data; 99718316Swollman 99837908Scharnier /* Withhold judgment when the short error 99918316Swollman * counters wrap or the interface is reset. 100018316Swollman */ 100118316Swollman if (ierr < 0 || in < 0 || oerr < 0 || out < 0) { 100218316Swollman LIM_SEC(ifinit_timer, 100318316Swollman now.tv_sec+CHECK_BAD_INTERVAL); 100418316Swollman continue; 100518316Swollman } 100618316Swollman 100718316Swollman /* Withhold judgement when there is no traffic 100818316Swollman */ 100918316Swollman if (in == 0 && out == 0 && ierr == 0 && oerr == 0) 101018316Swollman continue; 101118316Swollman 101218316Swollman /* It is bad if input or output is not working. 101318316Swollman * Require presistent problems before marking it dead. 101418316Swollman */ 101518316Swollman if ((in <= ierr && ierr > 0) 101618316Swollman || (out <= oerr && oerr > 0)) { 101718316Swollman if (!(ifp->int_state & IS_SICK)) { 101818316Swollman trace_act("interface %s to %s" 101918316Swollman " sick: in=%d ierr=%d" 102019880Swollman " out=%d oerr=%d", 102118316Swollman ifp->int_name, 102219880Swollman naddr_ntoa(ifp->int_dstaddr), 102318316Swollman in, ierr, out, oerr); 102418316Swollman if_sick(ifp); 102518316Swollman continue; 102618316Swollman } 102718316Swollman if (!(ifp->int_state & IS_BROKE)) { 102819880Swollman msglog("interface %s to %s broken:" 102918316Swollman " in=%d ierr=%d out=%d oerr=%d", 103018316Swollman ifp->int_name, 103119880Swollman naddr_ntoa(ifp->int_dstaddr), 103218316Swollman in, ierr, out, oerr); 103318316Swollman if_bad(ifp); 103418316Swollman } 103518316Swollman continue; 103618316Swollman } 103718316Swollman 103818316Swollman /* otherwise, it is active and healthy 103918316Swollman */ 104018316Swollman ifp->int_act_time = now.tv_sec; 104118316Swollman (void)if_ok(ifp, ""); 104218316Swollman continue; 104318316Swollman } 104418316Swollman 104518316Swollman /* This is a new interface. 104618316Swollman * If it is dead, forget it. 104718316Swollman */ 104846303Smarkm if (!iff_up(ifs.int_if_flags)) 104918316Swollman continue; 105018316Swollman 105119880Swollman /* If it duplicates an existing interface, 105219880Swollman * complain about it, mark the other one 105319880Swollman * duplicated, and forget this one. 105418316Swollman */ 105519880Swollman ifp = check_dup(ifs.int_addr,ifs.int_dstaddr,ifs.int_mask, 105619880Swollman ifs.int_if_flags); 105719880Swollman if (ifp != 0) { 105846303Smarkm /* Ignore duplicates of itself, caused by having 105946303Smarkm * IP aliases on the same network. 106046303Smarkm */ 106146303Smarkm if (!strcmp(ifp->int_name, ifs.int_name)) 106246303Smarkm continue; 106346303Smarkm 106418316Swollman if (!(prev_complaints & COMP_DUP)) { 106518316Swollman complaints |= COMP_DUP; 106620339Swollman msglog("%s (%s%s%s) is duplicated by" 106720339Swollman " %s (%s%s%s)", 106820339Swollman ifs.int_name, 106920339Swollman addrname(ifs.int_addr,ifs.int_mask,1), 107020339Swollman ((ifs.int_if_flags & IFF_POINTOPOINT) 107120339Swollman ? "-->" : ""), 107220339Swollman ((ifs.int_if_flags & IFF_POINTOPOINT) 107320339Swollman ? naddr_ntoa(ifs.int_dstaddr) : ""), 107420339Swollman ifp->int_name, 107520339Swollman addrname(ifp->int_addr,ifp->int_mask,1), 107620339Swollman ((ifp->int_if_flags & IFF_POINTOPOINT) 107720339Swollman ? "-->" : ""), 107820339Swollman ((ifp->int_if_flags & IFF_POINTOPOINT) 107920339Swollman ? naddr_ntoa(ifp->int_dstaddr) : "")); 108018316Swollman } 108118316Swollman ifp->int_state |= IS_DUP; 108219880Swollman continue; 108318316Swollman } 108418316Swollman 1085133715Sphk if (0 == (ifs.int_if_flags & (IFF_POINTOPOINT | IFF_BROADCAST | IFF_LOOPBACK))) { 108619880Swollman trace_act("%s is neither broadcast, point-to-point," 108719880Swollman " nor loopback", 108819880Swollman ifs.int_name); 108919880Swollman if (!(ifs.int_state & IFF_MULTICAST)) 109019880Swollman ifs.int_state |= IS_NO_RDISC; 109119880Swollman } 109218316Swollman 109319880Swollman 109419880Swollman /* It is new and ok. Add it to the list of interfaces 109518316Swollman */ 109646303Smarkm ifp = (struct interface *)rtmalloc(sizeof(*ifp), "ifinit ifp"); 109746303Smarkm memcpy(ifp, &ifs, sizeof(*ifp)); 109819880Swollman get_parms(ifp); 109919880Swollman if_link(ifp); 110018316Swollman trace_if("Add", ifp); 110118316Swollman 110218316Swollman /* Notice likely bad netmask. 110318316Swollman */ 110418316Swollman if (!(prev_complaints & COMP_NETMASK) 110519880Swollman && !(ifp->int_if_flags & IFF_POINTOPOINT) 110619880Swollman && ifp->int_addr != RIP_DEFAULT) { 1107190711Sphk LIST_FOREACH(ifp1, &ifnet, int_list) { 110818316Swollman if (ifp1->int_mask == ifp->int_mask) 110918316Swollman continue; 111018316Swollman if (ifp1->int_if_flags & IFF_POINTOPOINT) 111118316Swollman continue; 111219880Swollman if (ifp1->int_dstaddr == RIP_DEFAULT) 111319880Swollman continue; 111464483Ssheldonh /* ignore aliases on the right network */ 111564483Ssheldonh if (!strcmp(ifp->int_name, ifp1->int_name)) 111664483Ssheldonh continue; 111719880Swollman if (on_net(ifp->int_dstaddr, 111818316Swollman ifp1->int_net, ifp1->int_mask) 111919880Swollman || on_net(ifp1->int_dstaddr, 112018316Swollman ifp->int_net, ifp->int_mask)) { 112118316Swollman msglog("possible netmask problem" 112219880Swollman " between %s:%s and %s:%s", 112318316Swollman ifp->int_name, 112418316Swollman addrname(htonl(ifp->int_net), 112518316Swollman ifp->int_mask, 1), 112618316Swollman ifp1->int_name, 112718316Swollman addrname(htonl(ifp1->int_net), 112818316Swollman ifp1->int_mask, 1)); 112918316Swollman complaints |= COMP_NETMASK; 113018316Swollman } 113118316Swollman } 113218316Swollman } 113318316Swollman 113418316Swollman if (!(ifp->int_state & IS_ALIAS)) { 113519880Swollman /* Count the # of directly connected networks. 113619880Swollman */ 113718316Swollman if (!(ifp->int_if_flags & IFF_LOOPBACK)) 113818316Swollman tot_interfaces++; 113918316Swollman if (!IS_RIP_OFF(ifp->int_state)) 114018316Swollman rip_interfaces++; 114119880Swollman 114219880Swollman /* turn on router discovery and RIP If needed */ 114319880Swollman if_ok_rdisc(ifp); 114419880Swollman rip_on(ifp); 114518316Swollman } 114618316Swollman } 114718316Swollman 114819880Swollman /* If we are multi-homed and have at least two interfaces 114918316Swollman * listening to RIP, then output by default. 115018316Swollman */ 115118316Swollman if (!supplier_set && rip_interfaces > 1) 115218316Swollman set_supplier(); 115318316Swollman 115418316Swollman /* If we are multi-homed, optionally advertise a route to 115518316Swollman * our main address. 115618316Swollman */ 115718316Swollman if (advertise_mhome 115818316Swollman || (tot_interfaces > 1 115918316Swollman && mhome 116018316Swollman && (ifp = ifwithaddr(myaddr, 0, 0)) != 0 116118316Swollman && foundloopback)) { 116218316Swollman advertise_mhome = 1; 116318316Swollman rt = rtget(myaddr, HOST_MASK); 116418316Swollman if (rt != 0) { 116518316Swollman if (rt->rt_ifp != ifp 116618316Swollman || rt->rt_router != loopaddr) { 116718316Swollman rtdelete(rt); 116818316Swollman rt = 0; 116918316Swollman } else { 117046303Smarkm loop_rts.rts_ifp = ifp; 117146303Smarkm loop_rts.rts_metric = 0; 117246303Smarkm loop_rts.rts_time = rt->rt_time; 117318316Swollman rtchange(rt, rt->rt_state | RS_MHOME, 117446303Smarkm &loop_rts, 0); 117518316Swollman } 117618316Swollman } 117746303Smarkm if (rt == 0) { 117846303Smarkm loop_rts.rts_ifp = ifp; 117946303Smarkm loop_rts.rts_metric = 0; 118046303Smarkm rtadd(myaddr, HOST_MASK, RS_MHOME, &loop_rts); 118146303Smarkm } 118218316Swollman } 118318316Swollman 1184190711Sphk LIST_FOREACH_SAFE(ifp, &ifnet, int_list, ifp1) { 118518316Swollman /* Forget any interfaces that have disappeared. 118618316Swollman */ 118718316Swollman if (!(ifp->int_state & (IS_CHECKED | IS_REMOTE))) { 118819880Swollman trace_act("interface %s has disappeared", 118918316Swollman ifp->int_name); 119018316Swollman ifdel(ifp); 119118316Swollman continue; 119218316Swollman } 119318316Swollman 119418316Swollman if ((ifp->int_state & IS_BROKE) 119518316Swollman && !(ifp->int_state & IS_PASSIVE)) 119618316Swollman LIM_SEC(ifinit_timer, now.tv_sec+CHECK_BAD_INTERVAL); 119718316Swollman 119818316Swollman /* If we ever have a RIPv1 interface, assume we always will. 119918316Swollman * It might come back if it ever goes away. 120018316Swollman */ 120118316Swollman if (!(ifp->int_state & IS_NO_RIPV1_OUT) && supplier) 120218316Swollman have_ripv1_out = 1; 120318316Swollman if (!(ifp->int_state & IS_NO_RIPV1_IN)) 120418316Swollman have_ripv1_in = 1; 120518316Swollman } 120618316Swollman 1207190711Sphk LIST_FOREACH(ifp, &ifnet, int_list) { 120818316Swollman /* Ensure there is always a network route for interfaces, 120918316Swollman * after any dead interfaces have been deleted, which 121018316Swollman * might affect routes for point-to-point links. 121118316Swollman */ 121219880Swollman if (!addrouteforif(ifp)) 121319880Swollman continue; 121418316Swollman 121518316Swollman /* Add routes to the local end of point-to-point interfaces 121618316Swollman * using loopback. 121718316Swollman */ 121818316Swollman if ((ifp->int_if_flags & IFF_POINTOPOINT) 121918316Swollman && !(ifp->int_state & IS_REMOTE) 122018316Swollman && foundloopback) { 122118316Swollman /* Delete any routes to the network address through 122218316Swollman * foreign routers. Remove even static routes. 122318316Swollman */ 122446303Smarkm del_static(ifp->int_addr, HOST_MASK, 0, 0); 122518316Swollman rt = rtget(ifp->int_addr, HOST_MASK); 122618316Swollman if (rt != 0 && rt->rt_router != loopaddr) { 122718316Swollman rtdelete(rt); 122818316Swollman rt = 0; 122918316Swollman } 123018316Swollman if (rt != 0) { 123118316Swollman if (!(rt->rt_state & RS_LOCAL) 123218316Swollman || rt->rt_metric > ifp->int_metric) { 123318316Swollman ifp1 = ifp; 123418316Swollman } else { 123518316Swollman ifp1 = rt->rt_ifp; 123618316Swollman } 123746303Smarkm loop_rts.rts_ifp = ifp1; 123846303Smarkm loop_rts.rts_metric = 0; 123946303Smarkm loop_rts.rts_time = rt->rt_time; 124046303Smarkm rtchange(rt, ((rt->rt_state & ~RS_NET_SYN) 124146303Smarkm | (RS_IF|RS_LOCAL)), 124246303Smarkm &loop_rts, 0); 124318316Swollman } else { 124446303Smarkm loop_rts.rts_ifp = ifp; 124546303Smarkm loop_rts.rts_metric = 0; 124618316Swollman rtadd(ifp->int_addr, HOST_MASK, 124746303Smarkm (RS_IF | RS_LOCAL), &loop_rts); 124818316Swollman } 124918316Swollman } 125018316Swollman } 125118316Swollman 125218316Swollman /* add the authority routes */ 125318316Swollman for (intnetp = intnets; intnetp!=0; intnetp = intnetp->intnet_next) { 125418316Swollman rt = rtget(intnetp->intnet_addr, intnetp->intnet_mask); 125518316Swollman if (rt != 0 125618316Swollman && !(rt->rt_state & RS_NO_NET_SYN) 125718316Swollman && !(rt->rt_state & RS_NET_INT)) { 125818316Swollman rtdelete(rt); 125918316Swollman rt = 0; 126018316Swollman } 126146303Smarkm if (rt == 0) { 126246303Smarkm loop_rts.rts_ifp = 0; 126346303Smarkm loop_rts.rts_metric = intnetp->intnet_metric-1; 126418316Swollman rtadd(intnetp->intnet_addr, intnetp->intnet_mask, 126546303Smarkm RS_NET_SYN | RS_NET_INT, &loop_rts); 126646303Smarkm } 126718316Swollman } 126818316Swollman 126918316Swollman prev_complaints = complaints; 127018316Swollman} 127118316Swollman 127218316Swollman 127318316Swollmanstatic void 127418316Swollmancheck_net_syn(struct interface *ifp) 127518316Swollman{ 127618316Swollman struct rt_entry *rt; 127746303Smarkm static struct rt_spare new; 127818316Swollman 127918316Swollman 128018316Swollman /* Turn on the need to automatically synthesize a network route 128118316Swollman * for this interface only if we are running RIPv1 on some other 128218316Swollman * interface that is on a different class-A,B,or C network. 128318316Swollman */ 128418316Swollman if (have_ripv1_out || have_ripv1_in) { 128518316Swollman ifp->int_state |= IS_NEED_NET_SYN; 128618316Swollman rt = rtget(ifp->int_std_addr, ifp->int_std_mask); 128718316Swollman if (rt != 0 128818316Swollman && 0 == (rt->rt_state & RS_NO_NET_SYN) 128918316Swollman && (!(rt->rt_state & RS_NET_SYN) 129018316Swollman || rt->rt_metric > ifp->int_metric)) { 129118316Swollman rtdelete(rt); 129218316Swollman rt = 0; 129318316Swollman } 129446303Smarkm if (rt == 0) { 129546303Smarkm new.rts_ifp = ifp; 129646303Smarkm new.rts_gate = ifp->int_addr; 129746303Smarkm new.rts_router = ifp->int_addr; 129846303Smarkm new.rts_metric = ifp->int_metric; 129918316Swollman rtadd(ifp->int_std_addr, ifp->int_std_mask, 130046303Smarkm RS_NET_SYN, &new); 130146303Smarkm } 130218316Swollman 130318316Swollman } else { 130418316Swollman ifp->int_state &= ~IS_NEED_NET_SYN; 130518316Swollman 130618316Swollman rt = rtget(ifp->int_std_addr, 130718316Swollman ifp->int_std_mask); 130818316Swollman if (rt != 0 130918316Swollman && (rt->rt_state & RS_NET_SYN) 131018316Swollman && rt->rt_ifp == ifp) 131118316Swollman rtbad_sub(rt); 131218316Swollman } 131318316Swollman} 131418316Swollman 131518316Swollman 131618316Swollman/* Add route for interface if not currently installed. 131718316Swollman * Create route to other end if a point-to-point link, 131818316Swollman * otherwise a route to this (sub)network. 131918316Swollman */ 132019880Swollmanint /* 0=bad interface */ 132118316Swollmanaddrouteforif(struct interface *ifp) 132218316Swollman{ 132318316Swollman struct rt_entry *rt; 132446303Smarkm static struct rt_spare new; 132546303Smarkm naddr dst; 132618316Swollman 132718316Swollman 132818316Swollman /* skip sick interfaces 132918316Swollman */ 133018316Swollman if (ifp->int_state & IS_BROKE) 133119880Swollman return 0; 133218316Swollman 133318316Swollman /* If the interface on a subnet, then install a RIPv1 route to 133418316Swollman * the network as well (unless it is sick). 133518316Swollman */ 133618316Swollman if (ifp->int_state & IS_SUBNET) 133718316Swollman check_net_syn(ifp); 133818316Swollman 133919880Swollman dst = (0 != (ifp->int_if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) 134019880Swollman ? ifp->int_dstaddr 134119880Swollman : htonl(ifp->int_net)); 134218316Swollman 134346303Smarkm new.rts_ifp = ifp; 134446303Smarkm new.rts_router = ifp->int_addr; 134546303Smarkm new.rts_gate = ifp->int_addr; 134646303Smarkm new.rts_metric = ifp->int_metric; 134746303Smarkm new.rts_time = now.tv_sec; 134846303Smarkm 134919880Swollman /* If we are going to send packets to the gateway, 135019880Swollman * it must be reachable using our physical interfaces 135119880Swollman */ 135219880Swollman if ((ifp->int_state & IS_REMOTE) 135320339Swollman && !(ifp->int_state & IS_EXTERNAL) 135419880Swollman && !check_remote(ifp)) 135519880Swollman return 0; 135618316Swollman 135718316Swollman /* We are finished if the correct main interface route exists. 135818316Swollman * The right route must be for the right interface, not synthesized 135918316Swollman * from a subnet, be a "gateway" or not as appropriate, and so forth. 136018316Swollman */ 136146303Smarkm del_static(dst, ifp->int_mask, 0, 0); 136218316Swollman rt = rtget(dst, ifp->int_mask); 136318316Swollman if (rt != 0) { 136418316Swollman if ((rt->rt_ifp != ifp 136518316Swollman || rt->rt_router != ifp->int_addr) 136618316Swollman && (!(ifp->int_state & IS_DUP) 136718316Swollman || rt->rt_ifp == 0 136818316Swollman || (rt->rt_ifp->int_state & IS_BROKE))) { 136918316Swollman rtdelete(rt); 137018316Swollman rt = 0; 137118316Swollman } else { 137218316Swollman rtchange(rt, ((rt->rt_state | RS_IF) 137318316Swollman & ~(RS_NET_SYN | RS_LOCAL)), 137446303Smarkm &new, 0); 137518316Swollman } 137618316Swollman } 137718316Swollman if (rt == 0) { 137818316Swollman if (ifp->int_transitions++ > 0) 137919880Swollman trace_act("re-install interface %s", 138018316Swollman ifp->int_name); 138118316Swollman 138246303Smarkm rtadd(dst, ifp->int_mask, RS_IF, &new); 138318316Swollman } 138419880Swollman 138519880Swollman return 1; 138618316Swollman} 1387