if.c revision 46303
1261081Sasomers/*
2261081Sasomers * Copyright (c) 1983, 1993
3261081Sasomers *	The Regents of the University of California.  All rights reserved.
4261081Sasomers *
5261081Sasomers * Redistribution and use in source and binary forms, with or without
6261081Sasomers * modification, are permitted provided that the following conditions
7261081Sasomers * are met:
8261081Sasomers * 1. Redistributions of source code must retain the above copyright
9261081Sasomers *    notice, this list of conditions and the following disclaimer.
10261081Sasomers * 2. Redistributions in binary form must reproduce the above copyright
11261081Sasomers *    notice, this list of conditions and the following disclaimer in the
12261081Sasomers *    documentation and/or other materials provided with the distribution.
13261081Sasomers * 3. All advertising materials mentioning features or use of this software
14261081Sasomers *    must display the following acknowledgment:
15261081Sasomers *	This product includes software developed by the University of
16261081Sasomers *	California, Berkeley and its contributors.
17261081Sasomers * 4. Neither the name of the University nor the names of its contributors
18261081Sasomers *    may be used to endorse or promote products derived from this software
19261081Sasomers *    without specific prior written permission.
20261081Sasomers *
21261081Sasomers * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22261081Sasomers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23261081Sasomers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24261081Sasomers * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25261081Sasomers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26261081Sasomers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27261081Sasomers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28261081Sasomers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29261081Sasomers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30261081Sasomers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31261081Sasomers * SUCH DAMAGE.
32261081Sasomers *
33261081Sasomers *	$Id$
34261081Sasomers */
35261081Sasomers
36261081Sasomers#include "defs.h"
37261081Sasomers#include "pathnames.h"
38261081Sasomers
39261081Sasomers#if !defined(sgi) && !defined(__NetBSD__)
40261081Sasomersstatic char sccsid[] __attribute__((unused)) = "@(#)if.c	8.1 (Berkeley) 6/5/93";
41261081Sasomers#elif defined(__NetBSD__)
42261081Sasomers#include <sys/cdefs.h>
43261081Sasomers__RCSID("$NetBSD$");
44261081Sasomers#endif
45261081Sasomers#ident "$Revision: 2.17 $"
46262894Sasomers
47261081Sasomersstruct interface *ifnet;		/* all interfaces */
48261081Sasomers
49261081Sasomers/* hash table for all interfaces, big enough to tolerate ridiculous
50292820Sngie * numbers of IP aliases.  Crazy numbers of aliases such as 7000
51261081Sasomers * still will not do well, but not just in looking up interfaces
52261081Sasomers * by name or address.
53261081Sasomers */
54261081Sasomers#define AHASH_LEN 211			/* must be prime */
55261081Sasomers#define AHASH(a) &ahash_tbl[(a)%AHASH_LEN]
56261081Sasomersstruct interface *ahash_tbl[AHASH_LEN];
57261081Sasomers
58262894Sasomers#define BHASH_LEN 211			/* must be prime */
59261081Sasomers#define BHASH(a) &bhash_tbl[(a)%BHASH_LEN]
60261081Sasomersstruct interface *bhash_tbl[BHASH_LEN];
61261081Sasomers
62292820Sngiestruct interface *remote_if;		/* remote interfaces */
63261081Sasomers
64261081Sasomers/* hash for physical interface names.
65261081Sasomers * Assume there are never more 100 or 200 real interfaces, and that
66261081Sasomers * aliases are put on the end of the hash chains.
67261081Sasomers */
68261081Sasomers#define NHASH_LEN 97
69261081Sasomersstruct interface *nhash_tbl[NHASH_LEN];
70261081Sasomers
71261081Sasomersint	tot_interfaces;			/* # of remote and local interfaces */
72292820Sngieint	rip_interfaces;			/* # of interfaces doing RIP */
73261081Sasomersint	foundloopback;			/* valid flag for loopaddr */
74261081Sasomersnaddr	loopaddr;			/* our address on loopback */
75261081Sasomersstruct	rt_spare loop_rts;
76262894Sasomers
77261081Sasomersstruct timeval ifinit_timer;
78261081Sasomersstatic struct timeval last_ifinit;
79261081Sasomers#define IF_RESCAN_DELAY() (last_ifinit.tv_sec == now.tv_sec		\
80261081Sasomers			   && last_ifinit.tv_usec == now.tv_usec	\
81261081Sasomers			   && timercmp(&ifinit_timer, &now, >))
82261081Sasomers
83261081Sasomersint	have_ripv1_out;			/* have a RIPv1 interface */
84261081Sasomersint	have_ripv1_in;
85261081Sasomers
86261081Sasomers
87261081Sasomersstatic struct interface**
88261081Sasomersnhash(char *p)
89261081Sasomers{
90261081Sasomers	u_int i;
91261081Sasomers
92261081Sasomers	for (i = 0; *p != '\0'; p++) {
93261081Sasomers		i = ((i<<1) & 0x7fffffff) | ((i>>31) & 1);
94261081Sasomers		i ^= *p;
95261081Sasomers	}
96261081Sasomers	return &nhash_tbl[i % NHASH_LEN];
97261081Sasomers}
98261081Sasomers
99261081Sasomers
100261081Sasomers/* Link a new interface into the lists and hash tables.
101261081Sasomers */
102261081Sasomersvoid
103292820Sngieif_link(struct interface *ifp)
104261081Sasomers{
105261081Sasomers	struct interface **hifp;
106261081Sasomers
107261081Sasomers	ifp->int_prev = &ifnet;
108261081Sasomers	ifp->int_next = ifnet;
109261081Sasomers	if (ifnet != 0)
110261081Sasomers		ifnet->int_prev = &ifp->int_next;
111261081Sasomers	ifnet = ifp;
112261081Sasomers
113270228Sasomers	hifp = AHASH(ifp->int_addr);
114270228Sasomers	ifp->int_ahash_prev = hifp;
115270228Sasomers	if ((ifp->int_ahash = *hifp) != 0)
116261081Sasomers		(*hifp)->int_ahash_prev = &ifp->int_ahash;
117261081Sasomers	*hifp = ifp;
118261081Sasomers
119261081Sasomers	if (ifp->int_if_flags & IFF_BROADCAST) {
120261081Sasomers		hifp = BHASH(ifp->int_brdaddr);
121262894Sasomers		ifp->int_bhash_prev = hifp;
122261081Sasomers		if ((ifp->int_bhash = *hifp) != 0)
123261081Sasomers			(*hifp)->int_bhash_prev = &ifp->int_bhash;
124261081Sasomers		*hifp = ifp;
125261081Sasomers	}
126261081Sasomers
127261081Sasomers	if (ifp->int_state & IS_REMOTE) {
128261081Sasomers		ifp->int_rlink_prev = &remote_if;
129262894Sasomers		ifp->int_rlink = remote_if;
130261081Sasomers		if (remote_if != 0)
131261081Sasomers			remote_if->int_rlink_prev = &ifp->int_rlink;
132261081Sasomers		remote_if = ifp;
133261081Sasomers	}
134261081Sasomers
135261081Sasomers	hifp = nhash(ifp->int_name);
136262894Sasomers	if (ifp->int_state & IS_ALIAS) {
137261081Sasomers		/* put aliases on the end of the hash chain */
138262894Sasomers		while (*hifp != 0)
139261081Sasomers			hifp = &(*hifp)->int_nhash;
140261081Sasomers	}
141262133Sasomers	ifp->int_nhash_prev = hifp;
142261081Sasomers	if ((ifp->int_nhash = *hifp) != 0)
143261081Sasomers		(*hifp)->int_nhash_prev = &ifp->int_nhash;
144261081Sasomers	*hifp = ifp;
145261081Sasomers}
146261081Sasomers
147261081Sasomers
148261081Sasomers/* Find the interface with an address
149261081Sasomers */
150262894Sasomersstruct interface *
151261081Sasomersifwithaddr(naddr addr,
152261081Sasomers	   int	bcast,			/* notice IFF_BROADCAST address */
153270228Sasomers	   int	remote)			/* include IS_REMOTE interfaces */
154270228Sasomers{
155270228Sasomers	struct interface *ifp, *possible = 0;
156261081Sasomers
157270228Sasomers	remote = (remote == 0) ? IS_REMOTE : 0;
158261081Sasomers
159261081Sasomers	for (ifp = *AHASH(addr); ifp; ifp = ifp->int_ahash) {
160261081Sasomers		if (ifp->int_addr != addr)
161261081Sasomers			continue;
162261081Sasomers		if ((ifp->int_state & remote) != 0)
163261081Sasomers			continue;
164261081Sasomers		if ((ifp->int_state & (IS_BROKE | IS_PASSIVE)) == 0)
165261081Sasomers			return ifp;
166261081Sasomers		possible = ifp;
167262894Sasomers	}
168261081Sasomers
169261081Sasomers	if (possible || !bcast)
170261081Sasomers		return possible;
171262894Sasomers
172261081Sasomers	for (ifp = *BHASH(addr); ifp; ifp = ifp->int_bhash) {
173261081Sasomers		if (ifp->int_brdaddr != addr)
174261081Sasomers			continue;
175261081Sasomers		if ((ifp->int_state & remote) != 0)
176261081Sasomers			continue;
177261081Sasomers		if ((ifp->int_state & (IS_BROKE | IS_PASSIVE)) == 0)
178261081Sasomers			return ifp;
179261081Sasomers		possible = ifp;
180261081Sasomers	}
181261081Sasomers
182261081Sasomers	return possible;
183261081Sasomers}
184261081Sasomers
185261081Sasomers
186261081Sasomers/* find the interface with a name
187261081Sasomers */
188261081Sasomersstruct interface *
189261081Sasomersifwithname(char *name,			/* "ec0" or whatever */
190261081Sasomers	   naddr addr)			/* 0 or network address */
191261081Sasomers{
192261081Sasomers	struct interface *ifp;
193261081Sasomers
194261081Sasomers	for (;;) {
195261081Sasomers		for (ifp = *nhash(name); ifp != 0; ifp = ifp->int_nhash) {
196261081Sasomers			/* If the network address is not specified,
197261081Sasomers			 * ignore any alias interfaces.  Otherwise, look
198261081Sasomers			 * for the interface with the target name and address.
199261081Sasomers			 */
200261081Sasomers			if (!strcmp(ifp->int_name, name)
201261081Sasomers			    && ((addr == 0 && !(ifp->int_state & IS_ALIAS))
202261081Sasomers				|| (ifp->int_addr == addr)))
203261081Sasomers				return ifp;
204261081Sasomers		}
205261081Sasomers
206261081Sasomers		/* If there is no known interface, maybe there is a
207270228Sasomers		 * new interface.  So just once look for new interfaces.
208270228Sasomers		 */
209261081Sasomers		if (IF_RESCAN_DELAY())
210261081Sasomers			return 0;
211262894Sasomers		ifinit();
212261081Sasomers	}
213261081Sasomers}
214262894Sasomers
215261081Sasomers
216262894Sasomersstruct interface *
217261081Sasomersifwithindex(u_short index,
218261081Sasomers	    int rescan_ok)
219261081Sasomers{
220261081Sasomers	struct interface *ifp;
221261081Sasomers
222261081Sasomers	for (;;) {
223261081Sasomers		for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) {
224261081Sasomers			if (ifp->int_index == index)
225261081Sasomers				return ifp;
226261081Sasomers		}
227261081Sasomers
228261081Sasomers		/* If there is no known interface, maybe there is a
229261081Sasomers		 * new interface.  So just once look for new interfaces.
230261081Sasomers		 */
231261081Sasomers		if (!rescan_ok
232261081Sasomers		    || IF_RESCAN_DELAY())
233261081Sasomers			return 0;
234261081Sasomers		ifinit();
235261081Sasomers	}
236261081Sasomers}
237261081Sasomers
238261081Sasomers
239261081Sasomers/* Find an interface from which the specified address
240261081Sasomers * should have come from.  Used for figuring out which
241261081Sasomers * interface a packet came in on.
242292820Sngie */
243261081Sasomersstruct interface *
244261081Sasomersiflookup(naddr addr)
245261081Sasomers{
246261081Sasomers	struct interface *ifp, *maybe;
247261081Sasomers
248261081Sasomers	maybe = 0;
249261081Sasomers	for (;;) {
250261081Sasomers		for (ifp = ifnet; ifp; ifp = ifp->int_next) {
251261081Sasomers			if (ifp->int_if_flags & IFF_POINTOPOINT) {
252261081Sasomers				/* finished with a match */
253261081Sasomers				if (ifp->int_dstaddr == addr)
254261081Sasomers					return ifp;
255261081Sasomers
256261081Sasomers			} else {
257261081Sasomers				/* finished with an exact match */
258261081Sasomers				if (ifp->int_addr == addr)
259261081Sasomers					return ifp;
260261081Sasomers
261261081Sasomers				/* Look for the longest approximate match.
262261081Sasomers				 */
263261081Sasomers				if (on_net(addr, ifp->int_net, ifp->int_mask)
264261081Sasomers				    && (maybe == 0
265261081Sasomers					|| ifp->int_mask > maybe->int_mask))
266261081Sasomers					maybe = ifp;
267261081Sasomers			}
268261081Sasomers		}
269261081Sasomers
270261081Sasomers		if (maybe != 0
271261081Sasomers		    || IF_RESCAN_DELAY())
272261081Sasomers			return maybe;
273261081Sasomers
274261081Sasomers		/* If there is no known interface, maybe there is a
275261081Sasomers		 * new interface.  So just once look for new interfaces.
276261081Sasomers		 */
277261081Sasomers		ifinit();
278292820Sngie	}
279261081Sasomers}
280261081Sasomers
281261081Sasomers
282261081Sasomers/* Return the classical netmask for an IP address.
283261081Sasomers */
284270228Sasomersnaddr					/* host byte order */
285270228Sasomersstd_mask(naddr addr)			/* network byte order */
286261081Sasomers{
287261081Sasomers	NTOHL(addr);			/* was a host, not a network */
288261081Sasomers
289261081Sasomers	if (addr == 0)			/* default route has mask 0 */
290261081Sasomers		return 0;
291261081Sasomers	if (IN_CLASSA(addr))
292261081Sasomers		return IN_CLASSA_NET;
293261081Sasomers	if (IN_CLASSB(addr))
294261081Sasomers		return IN_CLASSB_NET;
295261081Sasomers	return IN_CLASSC_NET;
296261081Sasomers}
297261081Sasomers
298261081Sasomers
299261081Sasomers/* Find the netmask that would be inferred by RIPv1 listeners
300261081Sasomers *	on the given interface for a given network.
301261081Sasomers *	If no interface is specified, look for the best fitting	interface.
302261081Sasomers */
303261081Sasomersnaddr
304261081Sasomersripv1_mask_net(naddr addr,		/* in network byte order */
305261081Sasomers	       struct interface *ifp)	/* as seen on this interface */
306261081Sasomers{
307261081Sasomers	struct r1net *r1p;
308261081Sasomers	naddr mask = 0;
309261081Sasomers
310261081Sasomers	if (addr == 0)			/* default always has 0 mask */
311261081Sasomers		return mask;
312261081Sasomers
313261081Sasomers	if (ifp != 0 && ifp->int_ripv1_mask != HOST_MASK) {
314261081Sasomers		/* If the target network is that of the associated interface
315261081Sasomers		 * on which it arrived, then use the netmask of the interface.
316261081Sasomers		 */
317261081Sasomers		if (on_net(addr, ifp->int_net, ifp->int_std_mask))
318261081Sasomers			mask = ifp->int_ripv1_mask;
319261081Sasomers
320261081Sasomers	} else {
321261081Sasomers		/* Examine all interfaces, and if it the target seems
322261081Sasomers		 * to have the same network number of an interface, use the
323261081Sasomers		 * netmask of that interface.  If there is more than one
324261081Sasomers		 * such interface, prefer the interface with the longest
325261081Sasomers		 * match.
326261081Sasomers		 */
327261081Sasomers		for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) {
328261081Sasomers			if (on_net(addr, ifp->int_std_net, ifp->int_std_mask)
329261081Sasomers			    && ifp->int_ripv1_mask > mask
330261081Sasomers			    && ifp->int_ripv1_mask != HOST_MASK)
331261081Sasomers				mask = ifp->int_ripv1_mask;
332261081Sasomers		}
333261081Sasomers
334261081Sasomers	}
335261081Sasomers
336292820Sngie	/* check special definitions */
337261081Sasomers	if (mask == 0) {
338261081Sasomers		for (r1p = r1nets; r1p != 0; r1p = r1p->r1net_next) {
339261081Sasomers			if (on_net(addr, r1p->r1net_net, r1p->r1net_match)
340261081Sasomers			    && r1p->r1net_mask > mask)
341261081Sasomers				mask = r1p->r1net_mask;
342261081Sasomers		}
343262894Sasomers
344261081Sasomers		/* Otherwise, make the classic A/B/C guess.
345261081Sasomers		 */
346261081Sasomers		if (mask == 0)
347261081Sasomers			mask = std_mask(addr);
348261081Sasomers	}
349261081Sasomers
350261081Sasomers	return mask;
351261081Sasomers}
352261081Sasomers
353261081Sasomers
354261081Sasomersnaddr
355261081Sasomersripv1_mask_host(naddr addr,		/* in network byte order */
356261081Sasomers		struct interface *ifp)	/* as seen on this interface */
357261081Sasomers{
358261081Sasomers	naddr mask = ripv1_mask_net(addr, ifp);
359261081Sasomers
360261081Sasomers
361261081Sasomers	/* If the computed netmask does not mask the address,
362261081Sasomers	 * then assume it is a host address
363261081Sasomers	 */
364261081Sasomers	if ((ntohl(addr) & ~mask) != 0)
365261081Sasomers		mask = HOST_MASK;
366261081Sasomers	return mask;
367261081Sasomers}
368261081Sasomers
369261081Sasomers
370261081Sasomers/* See if a IP address looks reasonable as a destination
371261081Sasomers */
372292820Sngieint					/* 0=bad */
373262867Sasomerscheck_dst(naddr addr)
374262867Sasomers{
375262867Sasomers	NTOHL(addr);
376262867Sasomers
377262867Sasomers	if (IN_CLASSA(addr)) {
378261081Sasomers		if (addr == 0)
379261081Sasomers			return 1;	/* default */
380261081Sasomers
381261081Sasomers		addr >>= IN_CLASSA_NSHIFT;
382261081Sasomers		return (addr != 0 && addr != IN_LOOPBACKNET);
383261081Sasomers	}
384270228Sasomers
385270228Sasomers	return (IN_CLASSB(addr) || IN_CLASSC(addr));
386261081Sasomers}
387261081Sasomers
388261081Sasomers
389261081Sasomers/* See a new interface duplicates an existing interface.
390261081Sasomers */
391261081Sasomersstruct interface *
392261081Sasomerscheck_dup(naddr addr,			/* IP address, so network byte order */
393261081Sasomers	  naddr dstaddr,		/* ditto */
394261081Sasomers	  naddr mask,			/* mask, so host byte order */
395261081Sasomers	  int if_flags)
396261081Sasomers{
397261081Sasomers	struct interface *ifp;
398261081Sasomers
399261081Sasomers	for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) {
400271397Sasomers		if (ifp->int_mask != mask)
401270228Sasomers			continue;
402261081Sasomers
403261081Sasomers		if (!iff_up(ifp->int_if_flags))
404261081Sasomers			continue;
405261081Sasomers
406261081Sasomers		/* The local address can only be shared with a point-to-point
407261081Sasomers		 * link.
408261081Sasomers		 */
409261081Sasomers		if (ifp->int_addr == addr
410261081Sasomers		    && (((if_flags|ifp->int_if_flags) & IFF_POINTOPOINT) == 0))
411261081Sasomers			return ifp;
412261081Sasomers
413261081Sasomers		if (on_net(ifp->int_dstaddr, ntohl(dstaddr),mask))
414261081Sasomers			return ifp;
415261081Sasomers	}
416270228Sasomers	return 0;
417270228Sasomers}
418261081Sasomers
419261081Sasomers
420261081Sasomers/* See that a remote gateway is reachable.
421261081Sasomers *	Note that the answer can change as real interfaces come and go.
422261081Sasomers */
423261081Sasomersint					/* 0=bad */
424261081Sasomerscheck_remote(struct interface *ifp)
425261081Sasomers{
426261081Sasomers	struct rt_entry *rt;
427261081Sasomers
428261081Sasomers	/* do not worry about other kinds */
429261081Sasomers	if (!(ifp->int_state & IS_REMOTE))
430261081Sasomers	    return 1;
431270228Sasomers
432261081Sasomers	rt = rtfind(ifp->int_addr);
433261081Sasomers	if (rt != 0
434261081Sasomers	    && rt->rt_ifp != 0
435261081Sasomers	    &&on_net(ifp->int_addr,
436261081Sasomers		     rt->rt_ifp->int_net, rt->rt_ifp->int_mask))
437261081Sasomers		return 1;
438261081Sasomers
439261081Sasomers	/* the gateway cannot be reached directly from one of our
440261081Sasomers	 * interfaces
441261081Sasomers	 */
442261081Sasomers	if (!(ifp->int_state & IS_BROKE)) {
443261081Sasomers		msglog("unreachable gateway %s in "_PATH_GATEWAYS,
444261081Sasomers		       naddr_ntoa(ifp->int_addr));
445261081Sasomers		if_bad(ifp);
446261081Sasomers	}
447261081Sasomers	return 0;
448261081Sasomers}
449261081Sasomers
450261081Sasomers
451261081Sasomers/* Delete an interface.
452270228Sasomers */
453261081Sasomersstatic void
454261081Sasomersifdel(struct interface *ifp)
455261081Sasomers{
456261081Sasomers	struct ip_mreq m;
457261081Sasomers	struct interface *ifp1;
458261081Sasomers
459261081Sasomers
460261081Sasomers	trace_if("Del", ifp);
461261081Sasomers
462261081Sasomers	ifp->int_state |= IS_BROKE;
463261081Sasomers
464261081Sasomers	/* unlink the interface
465261081Sasomers	 */
466261081Sasomers	*ifp->int_prev = ifp->int_next;
467261081Sasomers	if (ifp->int_next != 0)
468261081Sasomers		ifp->int_next->int_prev = ifp->int_prev;
469261081Sasomers	*ifp->int_ahash_prev = ifp->int_ahash;
470261081Sasomers	if (ifp->int_ahash != 0)
471261081Sasomers		ifp->int_ahash->int_ahash_prev = ifp->int_ahash_prev;
472261081Sasomers	*ifp->int_nhash_prev = ifp->int_nhash;
473261081Sasomers	if (ifp->int_nhash != 0)
474261081Sasomers		ifp->int_nhash->int_nhash_prev = ifp->int_nhash_prev;
475270228Sasomers	if (ifp->int_if_flags & IFF_BROADCAST) {
476261081Sasomers		*ifp->int_bhash_prev = ifp->int_bhash;
477261081Sasomers		if (ifp->int_bhash != 0)
478261081Sasomers			ifp->int_bhash->int_bhash_prev = ifp->int_bhash_prev;
479261081Sasomers	}
480261081Sasomers	if (ifp->int_state & IS_REMOTE) {
481261081Sasomers		*ifp->int_rlink_prev = ifp->int_rlink;
482261081Sasomers		if (ifp->int_rlink != 0)
483261081Sasomers			ifp->int_rlink->int_rlink_prev = ifp->int_rlink_prev;
484261081Sasomers	}
485261081Sasomers
486261081Sasomers	if (!(ifp->int_state & IS_ALIAS)) {
487261081Sasomers		/* delete aliases when the main interface dies
488261081Sasomers		 */
489261081Sasomers		for (ifp1 = ifnet; 0 != ifp1; ifp1 = ifp1->int_next) {
490261081Sasomers			if (ifp1 != ifp
491261081Sasomers			    && !strcmp(ifp->int_name, ifp1->int_name))
492261081Sasomers				ifdel(ifp1);
493261081Sasomers		}
494261081Sasomers
495261081Sasomers		if ((ifp->int_if_flags & IFF_MULTICAST)
496261081Sasomers#ifdef MCAST_PPP_BUG
497261081Sasomers		    && !(ifp->int_if_flags & IFF_POINTOPOINT)
498261081Sasomers#endif
499261081Sasomers		    && rip_sock >= 0) {
500261081Sasomers			m.imr_multiaddr.s_addr = htonl(INADDR_RIP_GROUP);
501261081Sasomers			m.imr_interface.s_addr = ((ifp->int_if_flags
502261081Sasomers						   & IFF_POINTOPOINT)
503261081Sasomers						  ? ifp->int_dstaddr
504261081Sasomers						  : ifp->int_addr);
505261081Sasomers			if (setsockopt(rip_sock,IPPROTO_IP,IP_DROP_MEMBERSHIP,
506261081Sasomers				       &m, sizeof(m)) < 0
507270228Sasomers			    && errno != EADDRNOTAVAIL
508270228Sasomers			    && !TRACEACTIONS)
509261081Sasomers				LOGERR("setsockopt(IP_DROP_MEMBERSHIP RIP)");
510261081Sasomers			if (rip_sock_mcast == ifp)
511261081Sasomers				rip_sock_mcast = 0;
512261081Sasomers		}
513261081Sasomers		if (ifp->int_rip_sock >= 0) {
514261081Sasomers			(void)close(ifp->int_rip_sock);
515261081Sasomers			ifp->int_rip_sock = -1;
516261081Sasomers			fix_select();
517261081Sasomers		}
518270228Sasomers
519270228Sasomers		tot_interfaces--;
520261081Sasomers		if (!IS_RIP_OFF(ifp->int_state))
521261081Sasomers			rip_interfaces--;
522261081Sasomers
523261081Sasomers		/* Zap all routes associated with this interface.
524261081Sasomers		 * Assume routes just using gateways beyond this interface
525261081Sasomers		 * will timeout naturally, and have probably already died.
526261081Sasomers		 */
527261081Sasomers		(void)rn_walktree(rhead, walk_bad, 0);
528261081Sasomers
529261081Sasomers		set_rdisc_mg(ifp, 0);
530261081Sasomers		if_bad_rdisc(ifp);
531261081Sasomers	}
532261081Sasomers
533261081Sasomers	free(ifp);
534261081Sasomers}
535270228Sasomers
536261081Sasomers
537261081Sasomers/* Mark an interface ill.
538261081Sasomers */
539261081Sasomersvoid
540261081Sasomersif_sick(struct interface *ifp)
541261081Sasomers{
542261081Sasomers	if (0 == (ifp->int_state & (IS_SICK | IS_BROKE))) {
543261081Sasomers		ifp->int_state |= IS_SICK;
544261081Sasomers		ifp->int_act_time = NEVER;
545261081Sasomers		trace_if("Chg", ifp);
546261081Sasomers
547261081Sasomers		LIM_SEC(ifinit_timer, now.tv_sec+CHECK_BAD_INTERVAL);
548261081Sasomers	}
549261081Sasomers}
550261081Sasomers
551261081Sasomers
552261081Sasomers/* Mark an interface dead.
553261081Sasomers */
554261081Sasomersvoid
555261081Sasomersif_bad(struct interface *ifp)
556261081Sasomers{
557261081Sasomers	struct interface *ifp1;
558261081Sasomers
559261081Sasomers
560261081Sasomers	if (ifp->int_state & IS_BROKE)
561261081Sasomers		return;
562261081Sasomers
563261081Sasomers	LIM_SEC(ifinit_timer, now.tv_sec+CHECK_BAD_INTERVAL);
564292820Sngie
565261081Sasomers	ifp->int_state |= (IS_BROKE | IS_SICK);
566261081Sasomers	ifp->int_act_time = NEVER;
567261081Sasomers	ifp->int_query_time = NEVER;
568261081Sasomers	ifp->int_data.ts = now.tv_sec;
569261081Sasomers
570261081Sasomers	trace_if("Chg", ifp);
571261081Sasomers
572270228Sasomers	if (!(ifp->int_state & IS_ALIAS)) {
573261081Sasomers		for (ifp1 = ifnet; 0 != ifp1; ifp1 = ifp1->int_next) {
574261081Sasomers			if (ifp1 != ifp
575261081Sasomers			    && !strcmp(ifp->int_name, ifp1->int_name))
576261081Sasomers				if_bad(ifp1);
577261081Sasomers		}
578261081Sasomers		(void)rn_walktree(rhead, walk_bad, 0);
579261081Sasomers		if_bad_rdisc(ifp);
580261081Sasomers	}
581261081Sasomers}
582261081Sasomers
583261081Sasomers
584261081Sasomers/* Mark an interface alive
585261081Sasomers */
586261081Sasomersint					/* 1=it was dead */
587261081Sasomersif_ok(struct interface *ifp,
588261081Sasomers      const char *type)
589261081Sasomers{
590261081Sasomers	struct interface *ifp1;
591261081Sasomers
592261081Sasomers
593261081Sasomers	if (!(ifp->int_state & IS_BROKE)) {
594261081Sasomers		if (ifp->int_state & IS_SICK) {
595261081Sasomers			trace_act("%sinterface %s to %s working better",
596261081Sasomers				  type,
597261081Sasomers				  ifp->int_name, naddr_ntoa(ifp->int_dstaddr));
598261081Sasomers			ifp->int_state &= ~IS_SICK;
599261081Sasomers		}
600261081Sasomers		return 0;
601261081Sasomers	}
602261081Sasomers
603261081Sasomers	msglog("%sinterface %s to %s restored",
604261081Sasomers	       type, ifp->int_name, naddr_ntoa(ifp->int_dstaddr));
605261081Sasomers	ifp->int_state &= ~(IS_BROKE | IS_SICK);
606261081Sasomers	ifp->int_data.ts = 0;
607261081Sasomers
608261081Sasomers	if (!(ifp->int_state & IS_ALIAS)) {
609261081Sasomers		for (ifp1 = ifnet; 0 != ifp1; ifp1 = ifp1->int_next) {
610261081Sasomers			if (ifp1 != ifp
611261081Sasomers			    && !strcmp(ifp->int_name, ifp1->int_name))
612261081Sasomers				if_ok(ifp1, type);
613261081Sasomers		}
614261081Sasomers		if_ok_rdisc(ifp);
615261081Sasomers	}
616261081Sasomers
617261081Sasomers	if (ifp->int_state & IS_REMOTE) {
618261081Sasomers		if (!addrouteforif(ifp))
619261081Sasomers			return 0;
620261081Sasomers	}
621261081Sasomers	return 1;
622261081Sasomers}
623261081Sasomers
624261081Sasomers
625261081Sasomers/* disassemble routing message
626261081Sasomers */
627261081Sasomersvoid
628261081Sasomersrt_xaddrs(struct rt_addrinfo *info,
629270228Sasomers	  struct sockaddr *sa,
630270228Sasomers	  struct sockaddr *lim,
631261081Sasomers	  int addrs)
632261081Sasomers{
633261081Sasomers	int i;
634261081Sasomers#ifdef _HAVE_SA_LEN
635261081Sasomers	static struct sockaddr sa_zero;
636261081Sasomers#endif
637261081Sasomers#ifdef sgi
638261081Sasomers#define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(__uint64_t) - 1))) \
639261081Sasomers		    : sizeof(__uint64_t))
640261081Sasomers#else
641261081Sasomers#define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) \
642262894Sasomers		    : sizeof(long))
643261081Sasomers#endif
644261081Sasomers
645261081Sasomers
646261081Sasomers	memset(info, 0, sizeof(*info));
647261081Sasomers	info->rti_addrs = addrs;
648261081Sasomers	for (i = 0; i < RTAX_MAX && sa < lim; i++) {
649261081Sasomers		if ((addrs & (1 << i)) == 0)
650261081Sasomers			continue;
651261081Sasomers#ifdef _HAVE_SA_LEN
652261081Sasomers		info->rti_info[i] = (sa->sa_len != 0) ? sa : &sa_zero;
653261081Sasomers		sa = (struct sockaddr *)((char*)(sa)
654261081Sasomers					 + ROUNDUP(sa->sa_len));
655261081Sasomers#else
656261081Sasomers		info->rti_info[i] = sa;
657261081Sasomers		sa = (struct sockaddr *)((char*)(sa)
658261081Sasomers					 + ROUNDUP(_FAKE_SA_LEN_DST(sa)));
659261081Sasomers#endif
660270228Sasomers	}
661270228Sasomers}
662261081Sasomers
663261081Sasomers
664261081Sasomers/* Find the network interfaces which have configured themselves.
665261081Sasomers *	This must be done regularly, if only for extra addresses
666261081Sasomers *	that come and go on interfaces.
667261081Sasomers */
668261081Sasomersvoid
669261081Sasomersifinit(void)
670261081Sasomers{
671261081Sasomers	static char *sysctl_buf;
672261081Sasomers	static size_t sysctl_buf_size = 0;
673261081Sasomers	uint complaints = 0;
674292821Sngie	static u_int prev_complaints = 0;
675261081Sasomers#	define COMP_NOT_INET	0x001
676292821Sngie#	define COMP_NOADDR	0x002
677261081Sasomers#	define COMP_BADADDR	0x004
678261081Sasomers#	define COMP_NODST	0x008
679261081Sasomers#	define COMP_NOBADR	0x010
680261081Sasomers#	define COMP_NOMASK	0x020
681261081Sasomers#	define COMP_DUP		0x040
682262894Sasomers#	define COMP_BAD_METRIC	0x080
683261081Sasomers#	define COMP_NETMASK	0x100
684261081Sasomers
685261081Sasomers	struct interface ifs, ifs0, *ifp, *ifp1;
686261081Sasomers	struct rt_entry *rt;
687292821Sngie	size_t needed;
688292821Sngie	int mib[6];
689292821Sngie	struct if_msghdr *ifm;
690292821Sngie	struct ifa_msghdr *ifam, *ifam_lim, *ifam2;
691261081Sasomers	int in, ierr, out, oerr;
692261081Sasomers	struct intnet *intnetp;
693261081Sasomers	struct rt_addrinfo info;
694261081Sasomers#ifdef SIOCGIFMETRIC
695261081Sasomers	struct ifreq ifr;
696261081Sasomers#endif
697261081Sasomers
698261081Sasomers
699261081Sasomers	last_ifinit = now;
700261081Sasomers	ifinit_timer.tv_sec = now.tv_sec + (supplier
701261081Sasomers					    ? CHECK_ACT_INTERVAL
702261081Sasomers					    : CHECK_QUIET_INTERVAL);
703261081Sasomers
704261081Sasomers	/* mark all interfaces so we can get rid of those that disappear */
705261081Sasomers	for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next)
706261081Sasomers		ifp->int_state &= ~(IS_CHECKED | IS_DUP);
707261081Sasomers
708261081Sasomers	/* Fetch the interface list, without too many system calls
709261081Sasomers	 * since we do it repeatedly.
710261081Sasomers	 */
711292821Sngie	mib[0] = CTL_NET;
712292820Sngie	mib[1] = PF_ROUTE;
713261081Sasomers	mib[2] = 0;
714261081Sasomers	mib[3] = AF_INET;
715261081Sasomers	mib[4] = NET_RT_IFLIST;
716261081Sasomers	mib[5] = 0;
717261081Sasomers	for (;;) {
718292821Sngie		if ((needed = sysctl_buf_size) != 0) {
719292821Sngie			if (sysctl(mib, 6, sysctl_buf,&needed, 0, 0) >= 0)
720292821Sngie				break;
721270228Sasomers			/* retry if the table grew */
722270228Sasomers			if (errno != ENOMEM && errno != EFAULT)
723261081Sasomers				BADERR(1, "ifinit: sysctl(RT_IFLIST)");
724261081Sasomers			free(sysctl_buf);
725292820Sngie			needed = 0;
726261081Sasomers		}
727261081Sasomers		if (sysctl(mib, 6, 0, &needed, 0, 0) < 0)
728261081Sasomers			BADERR(1,"ifinit: sysctl(RT_IFLIST) estimate");
729261081Sasomers		sysctl_buf = rtmalloc(sysctl_buf_size = needed,
730261081Sasomers				      "ifinit sysctl");
731261081Sasomers	}
732261081Sasomers
733261081Sasomers	ifam_lim = (struct ifa_msghdr *)(sysctl_buf + needed);
734261081Sasomers	for (ifam = (struct ifa_msghdr *)sysctl_buf;
735261081Sasomers	     ifam < ifam_lim;
736262894Sasomers	     ifam = ifam2) {
737261081Sasomers
738261081Sasomers		ifam2 = (struct ifa_msghdr*)((char*)ifam + ifam->ifam_msglen);
739261081Sasomers
740261081Sasomers		if (ifam->ifam_type == RTM_IFINFO) {
741261081Sasomers			struct sockaddr_dl *sdl;
742261081Sasomers
743261081Sasomers			ifm = (struct if_msghdr *)ifam;
744261081Sasomers			/* make prototype structure for the IP aliases
745261081Sasomers			 */
746261081Sasomers			memset(&ifs0, 0, sizeof(ifs0));
747261081Sasomers			ifs0.int_rip_sock = -1;
748261081Sasomers			ifs0.int_index = ifm->ifm_index;
749261081Sasomers			ifs0.int_if_flags = ifm->ifm_flags;
750261081Sasomers			ifs0.int_state = IS_CHECKED;
751261081Sasomers			ifs0.int_query_time = NEVER;
752261081Sasomers			ifs0.int_act_time = now.tv_sec;
753270228Sasomers			ifs0.int_data.ts = now.tv_sec;
754270228Sasomers			ifs0.int_data.ipackets = ifm->ifm_data.ifi_ipackets;
755261081Sasomers			ifs0.int_data.ierrors = ifm->ifm_data.ifi_ierrors;
756261081Sasomers			ifs0.int_data.opackets = ifm->ifm_data.ifi_opackets;
757261081Sasomers			ifs0.int_data.oerrors = ifm->ifm_data.ifi_oerrors;
758261081Sasomers#ifdef sgi
759261081Sasomers			ifs0.int_data.odrops = ifm->ifm_data.ifi_odrops;
760261081Sasomers#endif
761286011Spluknet			sdl = (struct sockaddr_dl *)(ifm + 1);
762286011Spluknet			sdl->sdl_data[sdl->sdl_nlen] = 0;
763286011Spluknet			strncpy(ifs0.int_name, sdl->sdl_data,
764286011Spluknet				MIN(sizeof(ifs0.int_name), sdl->sdl_nlen));
765261081Sasomers			continue;
766286011Spluknet		}
767261081Sasomers		if (ifam->ifam_type != RTM_NEWADDR) {
768261081Sasomers			logbad(1,"ifinit: out of sync");
769270228Sasomers			continue;
770286011Spluknet		}
771286011Spluknet		rt_xaddrs(&info, (struct sockaddr *)(ifam+1),
772286011Spluknet			  (struct sockaddr *)ifam2,
773286011Spluknet			  ifam->ifam_addrs);
774286011Spluknet
775286011Spluknet		/* Prepare for the next address of this interface, which
776286011Spluknet		 * will be an alias.
777286011Spluknet		 * Do not output RIP or Router-Discovery packets via aliases.
778286011Spluknet		 */
779286011Spluknet		memcpy(&ifs, &ifs0, sizeof(ifs));
780286011Spluknet		ifs0.int_state |= (IS_ALIAS | IS_NO_RIP_OUT | IS_NO_RDISC);
781286011Spluknet
782286011Spluknet		if (INFO_IFA(&info) == 0) {
783286011Spluknet			if (iff_up(ifs.int_if_flags)) {
784286011Spluknet				if (!(prev_complaints & COMP_NOADDR))
785286011Spluknet					msglog("%s has no address",
786286011Spluknet					       ifs.int_name);
787286011Spluknet				complaints |= COMP_NOADDR;
788286011Spluknet			}
789261081Sasomers			continue;
790286011Spluknet		}
791261081Sasomers		if (INFO_IFA(&info)->sa_family != AF_INET) {
792261081Sasomers			if (iff_up(ifs.int_if_flags)) {
793270228Sasomers				if (!(prev_complaints & COMP_NOT_INET))
794286011Spluknet					trace_act("%s: not AF_INET",
795261081Sasomers						  ifs.int_name);
796261081Sasomers				complaints |= COMP_NOT_INET;
797261081Sasomers			}
798261081Sasomers			continue;
799261081Sasomers		}
800261081Sasomers
801286011Spluknet		ifs.int_addr = S_ADDR(INFO_IFA(&info));
802286011Spluknet
803286011Spluknet		if (ntohl(ifs.int_addr)>>24 == 0
804286011Spluknet		    || ntohl(ifs.int_addr)>>24 == 0xff) {
805286011Spluknet			if (iff_up(ifs.int_if_flags)) {
806261081Sasomers				if (!(prev_complaints & COMP_BADADDR))
807261081Sasomers					msglog("%s has a bad address",
808270228Sasomers					       ifs.int_name);
809286011Spluknet				complaints |= COMP_BADADDR;
810286011Spluknet			}
811286011Spluknet			continue;
812286011Spluknet		}
813286011Spluknet
814286011Spluknet		if (ifs.int_if_flags & IFF_LOOPBACK) {
815286011Spluknet			ifs.int_state |= IS_PASSIVE | IS_NO_RIP | IS_NO_RDISC;
816286011Spluknet			ifs.int_dstaddr = ifs.int_addr;
817286011Spluknet			ifs.int_mask = HOST_MASK;
818286011Spluknet			ifs.int_ripv1_mask = HOST_MASK;
819286011Spluknet			ifs.int_std_mask = std_mask(ifs.int_dstaddr);
820286011Spluknet			ifs.int_net = ntohl(ifs.int_dstaddr);
821286011Spluknet			if (!foundloopback) {
822286011Spluknet				foundloopback = 1;
823286011Spluknet				loopaddr = ifs.int_addr;
824286011Spluknet				loop_rts.rts_gate = loopaddr;
825286011Spluknet				loop_rts.rts_router = loopaddr;
826286011Spluknet			}
827286011Spluknet
828261081Sasomers		} else if (ifs.int_if_flags & IFF_POINTOPOINT) {
829292821Sngie			if (INFO_BRD(&info) == 0
830261081Sasomers			    || INFO_BRD(&info)->sa_family != AF_INET) {
831270228Sasomers				if (iff_up(ifs.int_if_flags)) {
832286011Spluknet					if (!(prev_complaints & COMP_NODST))
833261081Sasomers						msglog("%s has a bad"
834261081Sasomers						       " destination address",
835261081Sasomers						       ifs.int_name);
836261081Sasomers					complaints |= COMP_NODST;
837261081Sasomers				}
838261081Sasomers				continue;
839261081Sasomers			}
840261081Sasomers			ifs.int_dstaddr = S_ADDR(INFO_BRD(&info));
841261081Sasomers			if (ntohl(ifs.int_dstaddr)>>24 == 0
842261081Sasomers			    || ntohl(ifs.int_dstaddr)>>24 == 0xff) {
843262894Sasomers				if (iff_up(ifs.int_if_flags)) {
844261081Sasomers					if (!(prev_complaints & COMP_NODST))
845261081Sasomers						msglog("%s has a bad"
846261081Sasomers						       " destination address",
847261081Sasomers						       ifs.int_name);
848261081Sasomers					complaints |= COMP_NODST;
849261081Sasomers				}
850261081Sasomers				continue;
851261081Sasomers			}
852261081Sasomers			ifs.int_mask = HOST_MASK;
853261081Sasomers			ifs.int_ripv1_mask = ntohl(S_ADDR(INFO_MASK(&info)));
854261081Sasomers			ifs.int_std_mask = std_mask(ifs.int_dstaddr);
855261081Sasomers			ifs.int_net = ntohl(ifs.int_dstaddr);
856261081Sasomers
857261081Sasomers		}  else {
858261081Sasomers			if (INFO_MASK(&info) == 0) {
859261081Sasomers				if (iff_up(ifs.int_if_flags)) {
860261081Sasomers					if (!(prev_complaints & COMP_NOMASK))
861261081Sasomers						msglog("%s has no netmask",
862261081Sasomers						       ifs.int_name);
863261081Sasomers					complaints |= COMP_NOMASK;
864261081Sasomers				}
865261081Sasomers				continue;
866270228Sasomers			}
867270228Sasomers			ifs.int_dstaddr = ifs.int_addr;
868261081Sasomers			ifs.int_mask = ntohl(S_ADDR(INFO_MASK(&info)));
869261081Sasomers			ifs.int_ripv1_mask = ifs.int_mask;
870292820Sngie			ifs.int_std_mask = std_mask(ifs.int_addr);
871261081Sasomers			ifs.int_net = ntohl(ifs.int_addr) & ifs.int_mask;
872261081Sasomers			if (ifs.int_mask != ifs.int_std_mask)
873261081Sasomers				ifs.int_state |= IS_SUBNET;
874261081Sasomers
875261081Sasomers			if (ifs.int_if_flags & IFF_BROADCAST) {
876261081Sasomers				if (INFO_BRD(&info) == 0) {
877261081Sasomers					if (iff_up(ifs.int_if_flags)) {
878261081Sasomers					    if (!(prev_complaints
879261081Sasomers						  & COMP_NOBADR))
880261081Sasomers						msglog("%s has"
881261081Sasomers						       "no broadcast address",
882262894Sasomers						       ifs.int_name);
883261081Sasomers					    complaints |= COMP_NOBADR;
884261081Sasomers					}
885261081Sasomers					continue;
886261081Sasomers				}
887261081Sasomers				ifs.int_brdaddr = S_ADDR(INFO_BRD(&info));
888261081Sasomers			}
889261081Sasomers		}
890261081Sasomers		ifs.int_std_net = ifs.int_net & ifs.int_std_mask;
891261081Sasomers		ifs.int_std_addr = htonl(ifs.int_std_net);
892261081Sasomers
893261081Sasomers		/* Use a minimum metric of one.  Treat the interface metric
894261081Sasomers		 * (default 0) as an increment to the hop count of one.
895270228Sasomers		 *
896270228Sasomers		 * The metric obtained from the routing socket dump of
897261081Sasomers		 * interface addresses is wrong.  It is not set by the
898261081Sasomers		 * SIOCSIFMETRIC ioctl.
899292820Sngie		 */
900261081Sasomers#ifdef SIOCGIFMETRIC
901261081Sasomers		strncpy(ifr.ifr_name, ifs.int_name, sizeof(ifr.ifr_name));
902261081Sasomers		if (ioctl(rt_sock, SIOCGIFMETRIC, &ifr) < 0) {
903261081Sasomers			DBGERR(1, "ioctl(SIOCGIFMETRIC)");
904261081Sasomers			ifs.int_metric = 0;
905261081Sasomers		} else {
906261081Sasomers			ifs.int_metric = ifr.ifr_metric;
907261081Sasomers		}
908261081Sasomers#else
909261081Sasomers		ifs.int_metric = ifam->ifam_metric;
910261081Sasomers#endif
911262894Sasomers		if (ifs.int_metric > HOPCNT_INFINITY) {
912261081Sasomers			ifs.int_metric = 0;
913261081Sasomers			if (!(prev_complaints & COMP_BAD_METRIC)
914261081Sasomers			    && iff_up(ifs.int_if_flags)) {
915261081Sasomers				complaints |= COMP_BAD_METRIC;
916261081Sasomers				msglog("%s has a metric of %d",
917261081Sasomers				       ifs.int_name, ifs.int_metric);
918261081Sasomers			}
919261081Sasomers		}
920261081Sasomers
921261081Sasomers		/* See if this is a familiar interface.
922261081Sasomers		 * If so, stop worrying about it if it is the same.
923261081Sasomers		 * Start it over if it now is to somewhere else, as happens
924270228Sasomers		 * frequently with PPP and SLIP.
925270228Sasomers		 */
926261081Sasomers		ifp = ifwithname(ifs.int_name, ((ifs.int_state & IS_ALIAS)
927261081Sasomers						? ifs.int_addr
928261081Sasomers						: 0));
929292820Sngie		if (ifp != 0) {
930261081Sasomers			ifp->int_state |= IS_CHECKED;
931261081Sasomers
932261081Sasomers			if (0 != ((ifp->int_if_flags ^ ifs.int_if_flags)
933261081Sasomers				  & (IFF_BROADCAST
934261081Sasomers				     | IFF_LOOPBACK
935261081Sasomers				     | IFF_POINTOPOINT
936261081Sasomers				     | IFF_MULTICAST))
937261081Sasomers			    || 0 != ((ifp->int_state ^ ifs.int_state)
938261081Sasomers				     & IS_ALIAS)
939261081Sasomers			    || ifp->int_addr != ifs.int_addr
940261081Sasomers			    || ifp->int_brdaddr != ifs.int_brdaddr
941261081Sasomers			    || ifp->int_dstaddr != ifs.int_dstaddr
942261081Sasomers			    || ifp->int_mask != ifs.int_mask
943261081Sasomers			    || ifp->int_metric != ifs.int_metric) {
944261081Sasomers				/* Forget old information about
945261081Sasomers				 * a changed interface.
946261081Sasomers				 */
947261081Sasomers				trace_act("interface %s has changed",
948261081Sasomers					  ifp->int_name);
949261081Sasomers				ifdel(ifp);
950261081Sasomers				ifp = 0;
951261081Sasomers			}
952261081Sasomers		}
953261081Sasomers
954261081Sasomers		if (ifp != 0) {
955292820Sngie			/* The primary representative of an alias worries
956261081Sasomers			 * about how things are working.
957261081Sasomers			 */
958261081Sasomers			if (ifp->int_state & IS_ALIAS)
959261081Sasomers				continue;
960261081Sasomers
961261081Sasomers			/* note interfaces that have been turned off
962262894Sasomers			 */
963261081Sasomers			if (!iff_up(ifs.int_if_flags)) {
964264133Sjmmv				if (iff_up(ifp->int_if_flags)) {
965261081Sasomers					msglog("interface %s to %s turned off",
966261081Sasomers					       ifp->int_name,
967262894Sasomers					       naddr_ntoa(ifp->int_dstaddr));
968262894Sasomers					if_bad(ifp);
969261081Sasomers					ifp->int_if_flags &= ~IFF_UP;
970261081Sasomers				} else if (now.tv_sec>(ifp->int_data.ts
971261081Sasomers						       + CHECK_BAD_INTERVAL)) {
972261081Sasomers					trace_act("interface %s has been off"
973261081Sasomers						  " %ld seconds; forget it",
974261081Sasomers						  ifp->int_name,
975262894Sasomers						  now.tv_sec-ifp->int_data.ts);
976262894Sasomers					ifdel(ifp);
977262894Sasomers				}
978262894Sasomers				continue;
979261081Sasomers			}
980292820Sngie			/* or that were off and are now ok */
981261081Sasomers			if (!iff_up(ifp->int_if_flags)) {
982261081Sasomers				ifp->int_if_flags |= IFF_UP;
983261081Sasomers				(void)if_ok(ifp, "");
984262894Sasomers			}
985261081Sasomers
986261081Sasomers			/* If it has been long enough,
987261081Sasomers			 * see if the interface is broken.
988261081Sasomers			 */
989261081Sasomers			if (now.tv_sec < ifp->int_data.ts+CHECK_BAD_INTERVAL)
990261081Sasomers				continue;
991261081Sasomers
992261081Sasomers			in = ifs.int_data.ipackets - ifp->int_data.ipackets;
993261081Sasomers			ierr = ifs.int_data.ierrors - ifp->int_data.ierrors;
994261081Sasomers			out = ifs.int_data.opackets - ifp->int_data.opackets;
995261081Sasomers			oerr = ifs.int_data.oerrors - ifp->int_data.oerrors;
996261081Sasomers#ifdef sgi
997261081Sasomers			/* Through at least IRIX 6.2, PPP and SLIP
998261081Sasomers			 * count packets dropped by the filters.
999261081Sasomers			 * But FDDI rings stuck non-operational count
1000261081Sasomers			 * dropped packets as they wait for improvement.
1001261081Sasomers			 */
1002261081Sasomers			if (!(ifp->int_if_flags & IFF_POINTOPOINT))
1003261081Sasomers				oerr += (ifs.int_data.odrops
1004261081Sasomers					 - ifp->int_data.odrops);
1005261081Sasomers#endif
1006261081Sasomers			/* If the interface just awoke, restart the counters.
1007261081Sasomers			 */
1008292820Sngie			if (ifp->int_data.ts == 0) {
1009261081Sasomers				ifp->int_data = ifs.int_data;
1010261081Sasomers				continue;
1011261081Sasomers			}
1012261081Sasomers			ifp->int_data = ifs.int_data;
1013261081Sasomers
1014261081Sasomers			/* Withhold judgment when the short error
1015261081Sasomers			 * counters wrap or the interface is reset.
1016270228Sasomers			 */
1017270228Sasomers			if (ierr < 0 || in < 0 || oerr < 0 || out < 0) {
1018261081Sasomers				LIM_SEC(ifinit_timer,
1019261081Sasomers					now.tv_sec+CHECK_BAD_INTERVAL);
1020292820Sngie				continue;
1021261081Sasomers			}
1022261081Sasomers
1023261081Sasomers			/* Withhold judgement when there is no traffic
1024261081Sasomers			 */
1025261081Sasomers			if (in == 0 && out == 0 && ierr == 0 && oerr == 0)
1026261081Sasomers				continue;
1027261081Sasomers
1028261081Sasomers			/* It is bad if input or output is not working.
1029261081Sasomers			 * Require presistent problems before marking it dead.
1030261081Sasomers			 */
1031261081Sasomers			if ((in <= ierr && ierr > 0)
1032261081Sasomers			    || (out <= oerr && oerr > 0)) {
1033261081Sasomers				if (!(ifp->int_state & IS_SICK)) {
1034261081Sasomers					trace_act("interface %s to %s"
1035261081Sasomers						  " sick: in=%d ierr=%d"
1036261081Sasomers						  " out=%d oerr=%d",
1037261081Sasomers						  ifp->int_name,
1038261081Sasomers						  naddr_ntoa(ifp->int_dstaddr),
1039261081Sasomers						  in, ierr, out, oerr);
1040261081Sasomers					if_sick(ifp);
1041261081Sasomers					continue;
1042261081Sasomers				}
1043261081Sasomers				if (!(ifp->int_state & IS_BROKE)) {
1044261081Sasomers					msglog("interface %s to %s broken:"
1045261081Sasomers					       " in=%d ierr=%d out=%d oerr=%d",
1046261081Sasomers					       ifp->int_name,
1047261081Sasomers					       naddr_ntoa(ifp->int_dstaddr),
1048261081Sasomers					       in, ierr, out, oerr);
1049261081Sasomers					if_bad(ifp);
1050261081Sasomers				}
1051292820Sngie				continue;
1052261081Sasomers			}
1053261081Sasomers
1054261081Sasomers			/* otherwise, it is active and healthy
1055261081Sasomers			 */
1056261081Sasomers			ifp->int_act_time = now.tv_sec;
1057261081Sasomers			(void)if_ok(ifp, "");
1058261081Sasomers			continue;
1059261081Sasomers		}
1060261081Sasomers
1061261081Sasomers		/* This is a new interface.
1062261081Sasomers		 * If it is dead, forget it.
1063261081Sasomers		 */
1064261081Sasomers		if (!iff_up(ifs.int_if_flags))
1065261081Sasomers			continue;
1066261081Sasomers
1067261081Sasomers		/* If it duplicates an existing interface,
1068261081Sasomers		 * complain about it, mark the other one
1069261081Sasomers		 * duplicated, and forget this one.
1070261081Sasomers		 */
1071261081Sasomers		ifp = check_dup(ifs.int_addr,ifs.int_dstaddr,ifs.int_mask,
1072261081Sasomers				ifs.int_if_flags);
1073261081Sasomers		if (ifp != 0) {
1074261081Sasomers			/* Ignore duplicates of itself, caused by having
1075261081Sasomers			 * IP aliases on the same network.
1076261081Sasomers			 */
1077261081Sasomers			if (!strcmp(ifp->int_name, ifs.int_name))
1078261081Sasomers				continue;
1079261081Sasomers
1080261081Sasomers			if (!(prev_complaints & COMP_DUP)) {
1081261081Sasomers				complaints |= COMP_DUP;
1082261081Sasomers				msglog("%s (%s%s%s) is duplicated by"
1083261081Sasomers				       " %s (%s%s%s)",
1084261081Sasomers				       ifs.int_name,
1085261081Sasomers				       addrname(ifs.int_addr,ifs.int_mask,1),
1086261081Sasomers				       ((ifs.int_if_flags & IFF_POINTOPOINT)
1087261081Sasomers					? "-->" : ""),
1088261081Sasomers				       ((ifs.int_if_flags & IFF_POINTOPOINT)
1089261081Sasomers					? naddr_ntoa(ifs.int_dstaddr) : ""),
1090261081Sasomers				       ifp->int_name,
1091261081Sasomers				       addrname(ifp->int_addr,ifp->int_mask,1),
1092261081Sasomers				       ((ifp->int_if_flags & IFF_POINTOPOINT)
1093261081Sasomers					? "-->" : ""),
1094261081Sasomers				       ((ifp->int_if_flags & IFF_POINTOPOINT)
1095261081Sasomers					? naddr_ntoa(ifp->int_dstaddr) : ""));
1096261081Sasomers			}
1097261081Sasomers			ifp->int_state |= IS_DUP;
1098261081Sasomers			continue;
1099261081Sasomers		}
1100261081Sasomers
1101261081Sasomers		if (0 == (ifs.int_if_flags & (IFF_POINTOPOINT | IFF_BROADCAST))
1102261081Sasomers		    && !(ifs.int_state & IS_PASSIVE)) {
1103261081Sasomers			trace_act("%s is neither broadcast, point-to-point,"
1104261081Sasomers				  " nor loopback",
1105261081Sasomers				  ifs.int_name);
1106261081Sasomers			if (!(ifs.int_state & IFF_MULTICAST))
1107261081Sasomers				ifs.int_state |= IS_NO_RDISC;
1108261081Sasomers		}
1109261081Sasomers
1110261081Sasomers
1111261081Sasomers		/* It is new and ok.   Add it to the list of interfaces
1112261081Sasomers		 */
1113261081Sasomers		ifp = (struct interface *)rtmalloc(sizeof(*ifp), "ifinit ifp");
1114261081Sasomers		memcpy(ifp, &ifs, sizeof(*ifp));
1115261081Sasomers		get_parms(ifp);
1116261081Sasomers		if_link(ifp);
1117261081Sasomers		trace_if("Add", ifp);
1118261081Sasomers
1119261081Sasomers		/* Notice likely bad netmask.
1120261081Sasomers		 */
1121261081Sasomers		if (!(prev_complaints & COMP_NETMASK)
1122261081Sasomers		    && !(ifp->int_if_flags & IFF_POINTOPOINT)
1123261081Sasomers		    && ifp->int_addr != RIP_DEFAULT) {
1124261081Sasomers			for (ifp1 = ifnet; 0 != ifp1; ifp1 = ifp1->int_next) {
1125261081Sasomers				if (ifp1->int_mask == ifp->int_mask)
1126261081Sasomers					continue;
1127261081Sasomers				if (ifp1->int_if_flags & IFF_POINTOPOINT)
1128261081Sasomers					continue;
1129261081Sasomers				if (ifp1->int_dstaddr == RIP_DEFAULT)
1130261081Sasomers					continue;
1131261081Sasomers				if (on_net(ifp->int_dstaddr,
1132261081Sasomers					   ifp1->int_net, ifp1->int_mask)
1133261081Sasomers				    || on_net(ifp1->int_dstaddr,
1134261081Sasomers					      ifp->int_net, ifp->int_mask)) {
1135261081Sasomers					msglog("possible netmask problem"
1136261081Sasomers					       " between %s:%s and %s:%s",
1137261081Sasomers					       ifp->int_name,
1138261081Sasomers					       addrname(htonl(ifp->int_net),
1139261081Sasomers							ifp->int_mask, 1),
1140261081Sasomers					       ifp1->int_name,
1141261081Sasomers					       addrname(htonl(ifp1->int_net),
1142261081Sasomers							ifp1->int_mask, 1));
1143261081Sasomers					complaints |= COMP_NETMASK;
1144261081Sasomers				}
1145261081Sasomers			}
1146261081Sasomers		}
1147261081Sasomers
1148261081Sasomers		if (!(ifp->int_state & IS_ALIAS)) {
1149261081Sasomers			/* Count the # of directly connected networks.
1150261081Sasomers			 */
1151261081Sasomers			if (!(ifp->int_if_flags & IFF_LOOPBACK))
1152261081Sasomers				tot_interfaces++;
1153261081Sasomers			if (!IS_RIP_OFF(ifp->int_state))
1154261081Sasomers				rip_interfaces++;
1155261081Sasomers
1156261081Sasomers			/* turn on router discovery and RIP If needed */
1157261081Sasomers			if_ok_rdisc(ifp);
1158261081Sasomers			rip_on(ifp);
1159261081Sasomers		}
1160261081Sasomers	}
1161261081Sasomers
1162261081Sasomers	/* If we are multi-homed and have at least two interfaces
1163261081Sasomers	 * listening to RIP, then output by default.
1164261081Sasomers	 */
1165261081Sasomers	if (!supplier_set && rip_interfaces > 1)
1166261081Sasomers		set_supplier();
1167261081Sasomers
1168261081Sasomers	/* If we are multi-homed, optionally advertise a route to
1169261081Sasomers	 * our main address.
1170261081Sasomers	 */
1171261081Sasomers	if (advertise_mhome
1172261081Sasomers	    || (tot_interfaces > 1
1173261081Sasomers		&& mhome
1174261081Sasomers		&& (ifp = ifwithaddr(myaddr, 0, 0)) != 0
1175261081Sasomers		&& foundloopback)) {
1176261081Sasomers		advertise_mhome = 1;
1177261081Sasomers		rt = rtget(myaddr, HOST_MASK);
1178261081Sasomers		if (rt != 0) {
1179261081Sasomers			if (rt->rt_ifp != ifp
1180261081Sasomers			    || rt->rt_router != loopaddr) {
1181261081Sasomers				rtdelete(rt);
1182261081Sasomers				rt = 0;
1183261081Sasomers			} else {
1184261081Sasomers				loop_rts.rts_ifp = ifp;
1185261081Sasomers				loop_rts.rts_metric = 0;
1186261081Sasomers				loop_rts.rts_time = rt->rt_time;
1187261081Sasomers				rtchange(rt, rt->rt_state | RS_MHOME,
1188261081Sasomers					 &loop_rts, 0);
1189261081Sasomers			}
1190261081Sasomers		}
1191261081Sasomers		if (rt == 0) {
1192			loop_rts.rts_ifp = ifp;
1193			loop_rts.rts_metric = 0;
1194			rtadd(myaddr, HOST_MASK, RS_MHOME, &loop_rts);
1195		}
1196	}
1197
1198	for (ifp = ifnet; ifp != 0; ifp = ifp1) {
1199		ifp1 = ifp->int_next;	/* because we may delete it */
1200
1201		/* Forget any interfaces that have disappeared.
1202		 */
1203		if (!(ifp->int_state & (IS_CHECKED | IS_REMOTE))) {
1204			trace_act("interface %s has disappeared",
1205				  ifp->int_name);
1206			ifdel(ifp);
1207			continue;
1208		}
1209
1210		if ((ifp->int_state & IS_BROKE)
1211		    && !(ifp->int_state & IS_PASSIVE))
1212			LIM_SEC(ifinit_timer, now.tv_sec+CHECK_BAD_INTERVAL);
1213
1214		/* If we ever have a RIPv1 interface, assume we always will.
1215		 * It might come back if it ever goes away.
1216		 */
1217		if (!(ifp->int_state & IS_NO_RIPV1_OUT) && supplier)
1218			have_ripv1_out = 1;
1219		if (!(ifp->int_state & IS_NO_RIPV1_IN))
1220			have_ripv1_in = 1;
1221	}
1222
1223	for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) {
1224		/* Ensure there is always a network route for interfaces,
1225		 * after any dead interfaces have been deleted, which
1226		 * might affect routes for point-to-point links.
1227		 */
1228		if (!addrouteforif(ifp))
1229			continue;
1230
1231		/* Add routes to the local end of point-to-point interfaces
1232		 * using loopback.
1233		 */
1234		if ((ifp->int_if_flags & IFF_POINTOPOINT)
1235		    && !(ifp->int_state & IS_REMOTE)
1236		    && foundloopback) {
1237			/* Delete any routes to the network address through
1238			 * foreign routers. Remove even static routes.
1239			 */
1240			del_static(ifp->int_addr, HOST_MASK, 0, 0);
1241			rt = rtget(ifp->int_addr, HOST_MASK);
1242			if (rt != 0 && rt->rt_router != loopaddr) {
1243				rtdelete(rt);
1244				rt = 0;
1245			}
1246			if (rt != 0) {
1247				if (!(rt->rt_state & RS_LOCAL)
1248				    || rt->rt_metric > ifp->int_metric) {
1249					ifp1 = ifp;
1250				} else {
1251					ifp1 = rt->rt_ifp;
1252				}
1253				loop_rts.rts_ifp = ifp1;
1254				loop_rts.rts_metric = 0;
1255				loop_rts.rts_time = rt->rt_time;
1256				rtchange(rt, ((rt->rt_state & ~RS_NET_SYN)
1257					      | (RS_IF|RS_LOCAL)),
1258					 &loop_rts, 0);
1259			} else {
1260				loop_rts.rts_ifp = ifp;
1261				loop_rts.rts_metric = 0;
1262				rtadd(ifp->int_addr, HOST_MASK,
1263				      (RS_IF | RS_LOCAL), &loop_rts);
1264			}
1265		}
1266	}
1267
1268	/* add the authority routes */
1269	for (intnetp = intnets; intnetp!=0; intnetp = intnetp->intnet_next) {
1270		rt = rtget(intnetp->intnet_addr, intnetp->intnet_mask);
1271		if (rt != 0
1272		    && !(rt->rt_state & RS_NO_NET_SYN)
1273		    && !(rt->rt_state & RS_NET_INT)) {
1274			rtdelete(rt);
1275			rt = 0;
1276		}
1277		if (rt == 0) {
1278			loop_rts.rts_ifp = 0;
1279			loop_rts.rts_metric = intnetp->intnet_metric-1;
1280			rtadd(intnetp->intnet_addr, intnetp->intnet_mask,
1281			      RS_NET_SYN | RS_NET_INT, &loop_rts);
1282		}
1283	}
1284
1285	prev_complaints = complaints;
1286}
1287
1288
1289static void
1290check_net_syn(struct interface *ifp)
1291{
1292	struct rt_entry *rt;
1293	static struct rt_spare new;
1294
1295
1296	/* Turn on the need to automatically synthesize a network route
1297	 * for this interface only if we are running RIPv1 on some other
1298	 * interface that is on a different class-A,B,or C network.
1299	 */
1300	if (have_ripv1_out || have_ripv1_in) {
1301		ifp->int_state |= IS_NEED_NET_SYN;
1302		rt = rtget(ifp->int_std_addr, ifp->int_std_mask);
1303		if (rt != 0
1304		    && 0 == (rt->rt_state & RS_NO_NET_SYN)
1305		    && (!(rt->rt_state & RS_NET_SYN)
1306			|| rt->rt_metric > ifp->int_metric)) {
1307			rtdelete(rt);
1308			rt = 0;
1309		}
1310		if (rt == 0) {
1311			new.rts_ifp = ifp;
1312			new.rts_gate = ifp->int_addr;
1313			new.rts_router = ifp->int_addr;
1314			new.rts_metric = ifp->int_metric;
1315			rtadd(ifp->int_std_addr, ifp->int_std_mask,
1316			      RS_NET_SYN, &new);
1317		}
1318
1319	} else {
1320		ifp->int_state &= ~IS_NEED_NET_SYN;
1321
1322		rt = rtget(ifp->int_std_addr,
1323			   ifp->int_std_mask);
1324		if (rt != 0
1325		    && (rt->rt_state & RS_NET_SYN)
1326		    && rt->rt_ifp == ifp)
1327			rtbad_sub(rt);
1328	}
1329}
1330
1331
1332/* Add route for interface if not currently installed.
1333 * Create route to other end if a point-to-point link,
1334 * otherwise a route to this (sub)network.
1335 */
1336int					/* 0=bad interface */
1337addrouteforif(struct interface *ifp)
1338{
1339	struct rt_entry *rt;
1340	static struct rt_spare new;
1341	naddr dst;
1342
1343
1344	/* skip sick interfaces
1345	 */
1346	if (ifp->int_state & IS_BROKE)
1347		return 0;
1348
1349	/* If the interface on a subnet, then install a RIPv1 route to
1350	 * the network as well (unless it is sick).
1351	 */
1352	if (ifp->int_state & IS_SUBNET)
1353		check_net_syn(ifp);
1354
1355	dst = (0 != (ifp->int_if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK))
1356	       ? ifp->int_dstaddr
1357	       : htonl(ifp->int_net));
1358
1359	new.rts_ifp = ifp;
1360	new.rts_router = ifp->int_addr;
1361	new.rts_gate = ifp->int_addr;
1362	new.rts_metric = ifp->int_metric;
1363	new.rts_time = now.tv_sec;
1364
1365	/* If we are going to send packets to the gateway,
1366	 * it must be reachable using our physical interfaces
1367	 */
1368	if ((ifp->int_state & IS_REMOTE)
1369	    && !(ifp->int_state & IS_EXTERNAL)
1370	    && !check_remote(ifp))
1371		return 0;
1372
1373	/* We are finished if the correct main interface route exists.
1374	 * The right route must be for the right interface, not synthesized
1375	 * from a subnet, be a "gateway" or not as appropriate, and so forth.
1376	 */
1377	del_static(dst, ifp->int_mask, 0, 0);
1378	rt = rtget(dst, ifp->int_mask);
1379	if (rt != 0) {
1380		if ((rt->rt_ifp != ifp
1381		     || rt->rt_router != ifp->int_addr)
1382		    && (!(ifp->int_state & IS_DUP)
1383			|| rt->rt_ifp == 0
1384			|| (rt->rt_ifp->int_state & IS_BROKE))) {
1385			rtdelete(rt);
1386			rt = 0;
1387		} else {
1388			rtchange(rt, ((rt->rt_state | RS_IF)
1389				      & ~(RS_NET_SYN | RS_LOCAL)),
1390				 &new, 0);
1391		}
1392	}
1393	if (rt == 0) {
1394		if (ifp->int_transitions++ > 0)
1395			trace_act("re-install interface %s",
1396				  ifp->int_name);
1397
1398		rtadd(dst, ifp->int_mask, RS_IF, &new);
1399	}
1400
1401	return 1;
1402}
1403