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