xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.sbin/in.routed/if.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
3*0Sstevel@tonic-gate  * Use is subject to license terms.
4*0Sstevel@tonic-gate  *
5*0Sstevel@tonic-gate  * Copyright (c) 1983, 1993
6*0Sstevel@tonic-gate  *	The Regents of the University of California.  All rights reserved.
7*0Sstevel@tonic-gate  *
8*0Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
9*0Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
10*0Sstevel@tonic-gate  * are met:
11*0Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
12*0Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
13*0Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
14*0Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in the
15*0Sstevel@tonic-gate  *    documentation and/or other materials provided with the distribution.
16*0Sstevel@tonic-gate  * 3. All advertising materials mentioning features or use of this software
17*0Sstevel@tonic-gate  *    must display the following acknowledgment:
18*0Sstevel@tonic-gate  *	This product includes software developed by the University of
19*0Sstevel@tonic-gate  *	California, Berkeley and its contributors.
20*0Sstevel@tonic-gate  * 4. Neither the name of the University nor the names of its contributors
21*0Sstevel@tonic-gate  *    may be used to endorse or promote products derived from this software
22*0Sstevel@tonic-gate  *    without specific prior written permission.
23*0Sstevel@tonic-gate  *
24*0Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25*0Sstevel@tonic-gate  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26*0Sstevel@tonic-gate  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27*0Sstevel@tonic-gate  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28*0Sstevel@tonic-gate  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29*0Sstevel@tonic-gate  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30*0Sstevel@tonic-gate  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31*0Sstevel@tonic-gate  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32*0Sstevel@tonic-gate  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33*0Sstevel@tonic-gate  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34*0Sstevel@tonic-gate  * SUCH DAMAGE.
35*0Sstevel@tonic-gate  *
36*0Sstevel@tonic-gate  * $FreeBSD: src/sbin/routed/if.c,v 1.8 2000/08/11 08:24:38 sheldonh Exp $
37*0Sstevel@tonic-gate  */
38*0Sstevel@tonic-gate 
39*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
40*0Sstevel@tonic-gate 
41*0Sstevel@tonic-gate #include "defs.h"
42*0Sstevel@tonic-gate #include "pathnames.h"
43*0Sstevel@tonic-gate #include <sys/sockio.h>
44*0Sstevel@tonic-gate #include <inet/ip.h>
45*0Sstevel@tonic-gate #include <kstat.h>
46*0Sstevel@tonic-gate #include <stropts.h>
47*0Sstevel@tonic-gate #include <fcntl.h>
48*0Sstevel@tonic-gate #include <stddef.h>
49*0Sstevel@tonic-gate #include <assert.h>
50*0Sstevel@tonic-gate 
51*0Sstevel@tonic-gate /* linked list of all interfaces */
52*0Sstevel@tonic-gate struct interface *ifnet;
53*0Sstevel@tonic-gate 
54*0Sstevel@tonic-gate /*
55*0Sstevel@tonic-gate  * Acceptable sizes (in number of interfaces) for the interface hash
56*0Sstevel@tonic-gate  * tables.  These must all be prime.  The interface hash tables all
57*0Sstevel@tonic-gate  * start with a size of hash_table_sizes[0], and increase as needed.
58*0Sstevel@tonic-gate  */
59*0Sstevel@tonic-gate size_t hash_table_sizes[] = { 67, 131, 257, 521, 1031, 2053, 4099, 0 };
60*0Sstevel@tonic-gate 
61*0Sstevel@tonic-gate struct htbl {
62*0Sstevel@tonic-gate 	void		**htbl_ptrs;
63*0Sstevel@tonic-gate 	uint_t		(*htbl_hash)(const void *, size_t);
64*0Sstevel@tonic-gate 	size_t		htbl_link_off;	/* offset of the linkage structure */
65*0Sstevel@tonic-gate 	size_t		htbl_key_off;	/* offset of the key value (rehash) */
66*0Sstevel@tonic-gate 	size_t		htbl_size;	/* size of the hash */
67*0Sstevel@tonic-gate 	uint_t		htbl_size_index;
68*0Sstevel@tonic-gate 	uint_t		htbl_ifcount;	/* count of entries */
69*0Sstevel@tonic-gate 	boolean_t	htbl_grow;	/* growth allowed */
70*0Sstevel@tonic-gate };
71*0Sstevel@tonic-gate 
72*0Sstevel@tonic-gate /* Get first element -- for iteration */
73*0Sstevel@tonic-gate #define	HFIRST(htbl, arg) \
74*0Sstevel@tonic-gate 	((htbl)->htbl_ptrs[(htbl)->htbl_hash((arg), 0) % (htbl)->htbl_size])
75*0Sstevel@tonic-gate 
76*0Sstevel@tonic-gate /* Add an element to a hash */
77*0Sstevel@tonic-gate #define	HADD(htbl, strp) \
78*0Sstevel@tonic-gate 	hash_link((htbl), (htbl)->htbl_hash((strp), (htbl)->htbl_key_off), \
79*0Sstevel@tonic-gate 	    (strp))
80*0Sstevel@tonic-gate 
81*0Sstevel@tonic-gate uint_t	tot_interfaces;			/* # of remote and local interfaces */
82*0Sstevel@tonic-gate uint_t	rip_interfaces;			/* # of interfaces doing RIP */
83*0Sstevel@tonic-gate uint_t	ripout_interfaces;		/* # of interfaces advertising RIP */
84*0Sstevel@tonic-gate uint_t	fwd_interfaces;			/* # of interfaces ip_forwarding=1 */
85*0Sstevel@tonic-gate static boolean_t foundloopback;		/* valid flag for loopaddr */
86*0Sstevel@tonic-gate in_addr_t	loopaddr;		/* our address on loopback */
87*0Sstevel@tonic-gate static struct	rt_spare loop_rts;
88*0Sstevel@tonic-gate 
89*0Sstevel@tonic-gate struct timeval ifscan_timer;
90*0Sstevel@tonic-gate static struct timeval last_ifscan;
91*0Sstevel@tonic-gate #define	IF_RESCAN_DELAY() \
92*0Sstevel@tonic-gate 	(last_ifscan.tv_sec == now.tv_sec && \
93*0Sstevel@tonic-gate 	    last_ifscan.tv_usec == now.tv_usec && \
94*0Sstevel@tonic-gate 	    timercmp(&ifscan_timer, &now, > /* */))
95*0Sstevel@tonic-gate 
96*0Sstevel@tonic-gate boolean_t		have_ripv1_out;	/* have a RIPv1 interface */
97*0Sstevel@tonic-gate static boolean_t	have_ripv1_in;
98*0Sstevel@tonic-gate 
99*0Sstevel@tonic-gate static void		if_bad(struct interface *, boolean_t);
100*0Sstevel@tonic-gate static boolean_t	addrouteforif(struct interface *);
101*0Sstevel@tonic-gate static int	get_if_kstats(struct interface *, struct phyi_data *);
102*0Sstevel@tonic-gate static uint_t	ahash(const void *, uint_t);
103*0Sstevel@tonic-gate static uint_t	ihash(const void *, uint_t);
104*0Sstevel@tonic-gate static uint_t	nhash(const void *, uint_t);
105*0Sstevel@tonic-gate static void	htbl_grow(struct htbl *);
106*0Sstevel@tonic-gate 
107*0Sstevel@tonic-gate /*
108*0Sstevel@tonic-gate  * Table of all interfaces, hashed by interface address.  For remote
109*0Sstevel@tonic-gate  * interfaces, the gateway address is used.
110*0Sstevel@tonic-gate  */
111*0Sstevel@tonic-gate static struct htbl ahash_tbl = {
112*0Sstevel@tonic-gate     NULL, ahash, offsetof(struct interface, int_ahash),
113*0Sstevel@tonic-gate     offsetof(struct interface, int_addr),
114*0Sstevel@tonic-gate     0, 0, 0, _B_TRUE };
115*0Sstevel@tonic-gate /*
116*0Sstevel@tonic-gate  * Table of broadcast capable interfaces, hashed by interface broadcast
117*0Sstevel@tonic-gate  * address.
118*0Sstevel@tonic-gate  */
119*0Sstevel@tonic-gate static struct htbl bhash_tbl = {
120*0Sstevel@tonic-gate     NULL, ahash, offsetof(struct interface, int_bhash),
121*0Sstevel@tonic-gate     offsetof(struct interface, int_brdaddr),
122*0Sstevel@tonic-gate     0, 0, 0, _B_TRUE };
123*0Sstevel@tonic-gate /*
124*0Sstevel@tonic-gate  * Table of physical_interface structures (lists of interfaces by ifIndex),
125*0Sstevel@tonic-gate  * hashed by interface index.
126*0Sstevel@tonic-gate  */
127*0Sstevel@tonic-gate static struct htbl ihash_tbl = {
128*0Sstevel@tonic-gate     NULL, ihash, offsetof(struct physical_interface, phyi_link),
129*0Sstevel@tonic-gate     offsetof(struct physical_interface, phyi_index),
130*0Sstevel@tonic-gate     0, 0, 0, _B_TRUE };
131*0Sstevel@tonic-gate /*
132*0Sstevel@tonic-gate  * Table of all interfaces, hashed by interface name.
133*0Sstevel@tonic-gate  */
134*0Sstevel@tonic-gate static struct htbl nhash_tbl = {
135*0Sstevel@tonic-gate     NULL, nhash, offsetof(struct interface, int_nhash),
136*0Sstevel@tonic-gate     offsetof(struct interface, int_name),
137*0Sstevel@tonic-gate     0, 0, 0, _B_TRUE };
138*0Sstevel@tonic-gate 
139*0Sstevel@tonic-gate static struct physical_interface dummy_phyi;
140*0Sstevel@tonic-gate struct interface dummy_ifp;
141*0Sstevel@tonic-gate 
142*0Sstevel@tonic-gate /* Hash based on an IP address. */
143*0Sstevel@tonic-gate static uint_t
144*0Sstevel@tonic-gate ahash(const void *arg, size_t voffs)
145*0Sstevel@tonic-gate {
146*0Sstevel@tonic-gate 	/* LINTED */
147*0Sstevel@tonic-gate 	return ((uint_t)*(const in_addr_t *)((const char *)arg + voffs));
148*0Sstevel@tonic-gate }
149*0Sstevel@tonic-gate 
150*0Sstevel@tonic-gate static uint_t
151*0Sstevel@tonic-gate ihash(const void *arg, size_t voffs)
152*0Sstevel@tonic-gate {
153*0Sstevel@tonic-gate 	/* LINTED */
154*0Sstevel@tonic-gate 	return ((uint_t)*(const uint32_t *)((const char *)arg + voffs));
155*0Sstevel@tonic-gate }
156*0Sstevel@tonic-gate 
157*0Sstevel@tonic-gate static uint_t
158*0Sstevel@tonic-gate nhash(const void *arg, size_t voffs)
159*0Sstevel@tonic-gate {
160*0Sstevel@tonic-gate 	const char *cp = (const char *)arg + voffs;
161*0Sstevel@tonic-gate 	uint_t i;
162*0Sstevel@tonic-gate 
163*0Sstevel@tonic-gate 	for (i = 0; *cp != '\0'; cp++) {
164*0Sstevel@tonic-gate 		i = ((i<<1) & 0x7fffffff) | ((i>>30) & 0x00000003);
165*0Sstevel@tonic-gate 		i ^= *cp;
166*0Sstevel@tonic-gate 	}
167*0Sstevel@tonic-gate 	return (i);
168*0Sstevel@tonic-gate }
169*0Sstevel@tonic-gate 
170*0Sstevel@tonic-gate /*
171*0Sstevel@tonic-gate  * Add an element to the head of the list.
172*0Sstevel@tonic-gate  */
173*0Sstevel@tonic-gate static void
174*0Sstevel@tonic-gate link_in(void **head, void *strp, size_t loffs)
175*0Sstevel@tonic-gate {
176*0Sstevel@tonic-gate 	struct hlinkage *hlp;
177*0Sstevel@tonic-gate 
178*0Sstevel@tonic-gate 	/* LINTED: alignment known to be good. */
179*0Sstevel@tonic-gate 	hlp = (struct hlinkage *)((char *)strp + loffs);
180*0Sstevel@tonic-gate 	hlp->hl_prev = head;
181*0Sstevel@tonic-gate 	if ((hlp->hl_next = *head) != NULL) {
182*0Sstevel@tonic-gate 		/* LINTED */
183*0Sstevel@tonic-gate 		((struct hlinkage *)((char *)*head + loffs))->hl_prev =
184*0Sstevel@tonic-gate 		    &hlp->hl_next;
185*0Sstevel@tonic-gate 	}
186*0Sstevel@tonic-gate 	*head = strp;
187*0Sstevel@tonic-gate }
188*0Sstevel@tonic-gate 
189*0Sstevel@tonic-gate /* Remove from a list */
190*0Sstevel@tonic-gate static void
191*0Sstevel@tonic-gate link_out(void *strp, size_t loffs)
192*0Sstevel@tonic-gate {
193*0Sstevel@tonic-gate 	struct hlinkage *hlp;
194*0Sstevel@tonic-gate 
195*0Sstevel@tonic-gate 	/* LINTED: alignment known to be good. */
196*0Sstevel@tonic-gate 	hlp = (struct hlinkage *)((char *)strp + loffs);
197*0Sstevel@tonic-gate 	if ((*hlp->hl_prev = hlp->hl_next) != NULL) {
198*0Sstevel@tonic-gate 		/* LINTED */
199*0Sstevel@tonic-gate 		((struct hlinkage *)((char *)hlp->hl_next + loffs))->hl_prev =
200*0Sstevel@tonic-gate 		    hlp->hl_prev;
201*0Sstevel@tonic-gate 	}
202*0Sstevel@tonic-gate }
203*0Sstevel@tonic-gate 
204*0Sstevel@tonic-gate /* Add to a hash */
205*0Sstevel@tonic-gate static void
206*0Sstevel@tonic-gate hash_link(struct htbl *htbl, uint_t hval, void *strp)
207*0Sstevel@tonic-gate {
208*0Sstevel@tonic-gate 	void **hep;
209*0Sstevel@tonic-gate 
210*0Sstevel@tonic-gate 	if (htbl->htbl_grow && htbl->htbl_ifcount >= htbl->htbl_size * 5)
211*0Sstevel@tonic-gate 		htbl_grow(htbl);
212*0Sstevel@tonic-gate 
213*0Sstevel@tonic-gate 	hep = &htbl->htbl_ptrs[hval % htbl->htbl_size];
214*0Sstevel@tonic-gate 	link_in(hep, strp, htbl->htbl_link_off);
215*0Sstevel@tonic-gate 	htbl->htbl_ifcount++;
216*0Sstevel@tonic-gate }
217*0Sstevel@tonic-gate 
218*0Sstevel@tonic-gate /* Remove from a hash */
219*0Sstevel@tonic-gate static void
220*0Sstevel@tonic-gate hash_unlink(struct htbl *htbl, void *strp)
221*0Sstevel@tonic-gate {
222*0Sstevel@tonic-gate 	link_out(strp, htbl->htbl_link_off);
223*0Sstevel@tonic-gate 	htbl->htbl_ifcount--;
224*0Sstevel@tonic-gate }
225*0Sstevel@tonic-gate 
226*0Sstevel@tonic-gate static void
227*0Sstevel@tonic-gate dummy_ifp_init(void)
228*0Sstevel@tonic-gate {
229*0Sstevel@tonic-gate 	dummy_phyi.phyi_interface = &dummy_ifp;
230*0Sstevel@tonic-gate 	dummy_ifp.int_phys = &dummy_phyi;
231*0Sstevel@tonic-gate 	(void) strcpy(dummy_phyi.phyi_name, "wildcard");
232*0Sstevel@tonic-gate 	(void) strcpy(dummy_ifp.int_name, "wildcard");
233*0Sstevel@tonic-gate 	dummy_ifp.int_dstaddr = dummy_ifp.int_addr = INADDR_NONE;
234*0Sstevel@tonic-gate 	dummy_ifp.int_mask = IP_HOST_MASK;
235*0Sstevel@tonic-gate 	dummy_ifp.int_metric = HOPCNT_INFINITY;
236*0Sstevel@tonic-gate 	dummy_ifp.int_state = (IS_BROKE|IS_PASSIVE|IS_NO_RIP|IS_NO_RDISC);
237*0Sstevel@tonic-gate 	dummy_ifp.int_std_mask = std_mask(dummy_ifp.int_addr);
238*0Sstevel@tonic-gate 	dummy_ifp.int_std_net = dummy_ifp.int_net & dummy_ifp.int_std_mask;
239*0Sstevel@tonic-gate 	dummy_ifp.int_std_addr = htonl(dummy_ifp.int_std_net);
240*0Sstevel@tonic-gate }
241*0Sstevel@tonic-gate 
242*0Sstevel@tonic-gate /* allocate the interface hash tables */
243*0Sstevel@tonic-gate void
244*0Sstevel@tonic-gate iftbl_alloc(void)
245*0Sstevel@tonic-gate {
246*0Sstevel@tonic-gate 	size_t initial_size = hash_table_sizes[0];
247*0Sstevel@tonic-gate 
248*0Sstevel@tonic-gate 	errno = 0;
249*0Sstevel@tonic-gate 	ahash_tbl.htbl_ptrs = calloc(initial_size, sizeof (void *));
250*0Sstevel@tonic-gate 	bhash_tbl.htbl_ptrs = calloc(initial_size, sizeof (void *));
251*0Sstevel@tonic-gate 	ihash_tbl.htbl_ptrs = calloc(initial_size, sizeof (void *));
252*0Sstevel@tonic-gate 	nhash_tbl.htbl_ptrs = calloc(initial_size, sizeof (void *));
253*0Sstevel@tonic-gate 
254*0Sstevel@tonic-gate 	if (errno != 0)
255*0Sstevel@tonic-gate 		BADERR(_B_FALSE, "Unable to allocate interface tables");
256*0Sstevel@tonic-gate 
257*0Sstevel@tonic-gate 	ahash_tbl.htbl_size = initial_size;
258*0Sstevel@tonic-gate 	bhash_tbl.htbl_size = initial_size;
259*0Sstevel@tonic-gate 	ihash_tbl.htbl_size = initial_size;
260*0Sstevel@tonic-gate 	nhash_tbl.htbl_size = initial_size;
261*0Sstevel@tonic-gate 
262*0Sstevel@tonic-gate 	dummy_ifp_init();
263*0Sstevel@tonic-gate }
264*0Sstevel@tonic-gate 
265*0Sstevel@tonic-gate 
266*0Sstevel@tonic-gate static void
267*0Sstevel@tonic-gate htbl_grow(struct htbl *htbl)
268*0Sstevel@tonic-gate {
269*0Sstevel@tonic-gate 	void *strp;
270*0Sstevel@tonic-gate 	void **new_ptrs, **saved_old_ptrs, **old_ptrs;
271*0Sstevel@tonic-gate 	size_t new_size, old_size;
272*0Sstevel@tonic-gate 	static uint_t failed_count;
273*0Sstevel@tonic-gate 
274*0Sstevel@tonic-gate 	if ((new_size = hash_table_sizes[htbl->htbl_size_index + 1]) == 0)
275*0Sstevel@tonic-gate 		return;
276*0Sstevel@tonic-gate 
277*0Sstevel@tonic-gate 	if ((new_ptrs = calloc(new_size, sizeof (void *))) == NULL) {
278*0Sstevel@tonic-gate 		/*
279*0Sstevel@tonic-gate 		 * This is not fatal since we already have a
280*0Sstevel@tonic-gate 		 * functional, yet crowded, interface table.
281*0Sstevel@tonic-gate 		 */
282*0Sstevel@tonic-gate 		if (++failed_count % 100 == 1)
283*0Sstevel@tonic-gate 			msglog("%sunable to grow interface hash table: %s",
284*0Sstevel@tonic-gate 			    failed_count > 1 ? "Still " : "",
285*0Sstevel@tonic-gate 			    rip_strerror(errno));
286*0Sstevel@tonic-gate 		return;
287*0Sstevel@tonic-gate 	}
288*0Sstevel@tonic-gate 
289*0Sstevel@tonic-gate 	failed_count = 0;
290*0Sstevel@tonic-gate 
291*0Sstevel@tonic-gate 	saved_old_ptrs = old_ptrs = htbl->htbl_ptrs;
292*0Sstevel@tonic-gate 	old_size = htbl->htbl_size;
293*0Sstevel@tonic-gate 	htbl->htbl_ptrs = new_ptrs;
294*0Sstevel@tonic-gate 	htbl->htbl_size = new_size;
295*0Sstevel@tonic-gate 	htbl->htbl_size_index++;
296*0Sstevel@tonic-gate 	htbl->htbl_ifcount = 0;
297*0Sstevel@tonic-gate 
298*0Sstevel@tonic-gate 	/*
299*0Sstevel@tonic-gate 	 * Go through the list of structures, and re-link each into
300*0Sstevel@tonic-gate 	 * this new table.
301*0Sstevel@tonic-gate 	 */
302*0Sstevel@tonic-gate 	htbl->htbl_grow = _B_FALSE;
303*0Sstevel@tonic-gate 	while (old_size-- > 0) {
304*0Sstevel@tonic-gate 		strp = *old_ptrs++;
305*0Sstevel@tonic-gate 		HADD(htbl, strp);
306*0Sstevel@tonic-gate 	}
307*0Sstevel@tonic-gate 
308*0Sstevel@tonic-gate 	htbl->htbl_grow = _B_TRUE;
309*0Sstevel@tonic-gate 	free(saved_old_ptrs);
310*0Sstevel@tonic-gate }
311*0Sstevel@tonic-gate 
312*0Sstevel@tonic-gate /* Link a new interface into the lists and hash tables. */
313*0Sstevel@tonic-gate void
314*0Sstevel@tonic-gate if_link(struct interface *ifp, uint32_t ifindex)
315*0Sstevel@tonic-gate {
316*0Sstevel@tonic-gate 	struct physical_interface *phyi;
317*0Sstevel@tonic-gate 
318*0Sstevel@tonic-gate 	link_in((void **)&ifnet, ifp, offsetof(struct interface, int_link));
319*0Sstevel@tonic-gate 
320*0Sstevel@tonic-gate 	HADD(&ahash_tbl, ifp);
321*0Sstevel@tonic-gate 	HADD(&nhash_tbl, ifp);
322*0Sstevel@tonic-gate 
323*0Sstevel@tonic-gate 	if (ifp->int_if_flags & IFF_BROADCAST)
324*0Sstevel@tonic-gate 		HADD(&bhash_tbl, ifp);
325*0Sstevel@tonic-gate 
326*0Sstevel@tonic-gate 	if (ifindex != 0) {
327*0Sstevel@tonic-gate 		for (phyi = HFIRST(&ihash_tbl, &ifindex);
328*0Sstevel@tonic-gate 		    phyi != NULL; phyi = phyi->phyi_link.hl_next) {
329*0Sstevel@tonic-gate 			if (phyi->phyi_index == ifindex)
330*0Sstevel@tonic-gate 				break;
331*0Sstevel@tonic-gate 		}
332*0Sstevel@tonic-gate 		if (phyi == NULL) {
333*0Sstevel@tonic-gate 			size_t size;
334*0Sstevel@tonic-gate 
335*0Sstevel@tonic-gate 			phyi = rtmalloc(sizeof (*phyi), "physical_interface");
336*0Sstevel@tonic-gate 			(void) memset(phyi, 0, sizeof (*phyi));
337*0Sstevel@tonic-gate 			phyi->phyi_index = ifindex;
338*0Sstevel@tonic-gate 			/* LINTED */
339*0Sstevel@tonic-gate 			assert(IF_NAME_LEN >= IF_NAMESIZE);
340*0Sstevel@tonic-gate 
341*0Sstevel@tonic-gate 			size = strcspn(ifp->int_name, ":");
342*0Sstevel@tonic-gate 			(void) strncpy(phyi->phyi_name, ifp->int_name,
343*0Sstevel@tonic-gate 			    size);
344*0Sstevel@tonic-gate 			phyi->phyi_name[size] = '\0';
345*0Sstevel@tonic-gate 			HADD(&ihash_tbl, phyi);
346*0Sstevel@tonic-gate 		}
347*0Sstevel@tonic-gate 		link_in((void **)&phyi->phyi_interface, ifp,
348*0Sstevel@tonic-gate 		    offsetof(struct interface, int_ilist));
349*0Sstevel@tonic-gate 		ifp->int_phys = phyi;
350*0Sstevel@tonic-gate 	}
351*0Sstevel@tonic-gate }
352*0Sstevel@tonic-gate 
353*0Sstevel@tonic-gate /* Find the interface with an address */
354*0Sstevel@tonic-gate struct interface *
355*0Sstevel@tonic-gate ifwithaddr(in_addr_t addr,
356*0Sstevel@tonic-gate     boolean_t bcast,	/* notice IFF_BROADCAST address */
357*0Sstevel@tonic-gate     boolean_t remote)	/* include IS_REMOTE interfaces */
358*0Sstevel@tonic-gate {
359*0Sstevel@tonic-gate 	struct interface *ifp, *possible = NULL;
360*0Sstevel@tonic-gate 	uint32_t remote_state;
361*0Sstevel@tonic-gate 
362*0Sstevel@tonic-gate 	remote_state = (!remote ? IS_REMOTE : 0);
363*0Sstevel@tonic-gate 
364*0Sstevel@tonic-gate 	for (ifp = HFIRST(&ahash_tbl, &addr); ifp != NULL;
365*0Sstevel@tonic-gate 	    ifp = ifp->int_ahash.hl_next) {
366*0Sstevel@tonic-gate 		if (ifp->int_addr != addr)
367*0Sstevel@tonic-gate 			continue;
368*0Sstevel@tonic-gate 		if (ifp->int_state & remote_state)
369*0Sstevel@tonic-gate 			continue;
370*0Sstevel@tonic-gate 		if (!(ifp->int_state & (IS_BROKE | IS_PASSIVE)))
371*0Sstevel@tonic-gate 			return (ifp);
372*0Sstevel@tonic-gate 		possible = ifp;
373*0Sstevel@tonic-gate 	}
374*0Sstevel@tonic-gate 
375*0Sstevel@tonic-gate 	if (possible != NULL || !bcast)
376*0Sstevel@tonic-gate 		return (possible);
377*0Sstevel@tonic-gate 
378*0Sstevel@tonic-gate 	for (ifp = HFIRST(&bhash_tbl, &addr); ifp != NULL;
379*0Sstevel@tonic-gate 	    ifp = ifp->int_bhash.hl_next) {
380*0Sstevel@tonic-gate 		if (ifp->int_brdaddr != addr)
381*0Sstevel@tonic-gate 			continue;
382*0Sstevel@tonic-gate 		if (ifp->int_state & remote_state)
383*0Sstevel@tonic-gate 			continue;
384*0Sstevel@tonic-gate 		if (!(ifp->int_state & (IS_BROKE | IS_PASSIVE)))
385*0Sstevel@tonic-gate 			return (ifp);
386*0Sstevel@tonic-gate 		possible = ifp;
387*0Sstevel@tonic-gate 	}
388*0Sstevel@tonic-gate 
389*0Sstevel@tonic-gate 	return (possible);
390*0Sstevel@tonic-gate }
391*0Sstevel@tonic-gate 
392*0Sstevel@tonic-gate 
393*0Sstevel@tonic-gate /* find the interface with the specified name ("hme0" for example) */
394*0Sstevel@tonic-gate struct interface *
395*0Sstevel@tonic-gate ifwithname(const char *name)
396*0Sstevel@tonic-gate {
397*0Sstevel@tonic-gate 	struct interface *ifp;
398*0Sstevel@tonic-gate 
399*0Sstevel@tonic-gate 	for (;;) {
400*0Sstevel@tonic-gate 		for (ifp = HFIRST(&nhash_tbl, name); ifp != NULL;
401*0Sstevel@tonic-gate 		    ifp = ifp->int_nhash.hl_next) {
402*0Sstevel@tonic-gate 			if (strcmp(ifp->int_name, name) == 0)
403*0Sstevel@tonic-gate 				return (ifp);
404*0Sstevel@tonic-gate 		}
405*0Sstevel@tonic-gate 
406*0Sstevel@tonic-gate 		/*
407*0Sstevel@tonic-gate 		 * If there is no known interface, maybe there is a
408*0Sstevel@tonic-gate 		 * new interface.  So just once look for new interfaces.
409*0Sstevel@tonic-gate 		 */
410*0Sstevel@tonic-gate 		if (IF_RESCAN_DELAY())
411*0Sstevel@tonic-gate 			return (NULL);
412*0Sstevel@tonic-gate 		ifscan();
413*0Sstevel@tonic-gate 	}
414*0Sstevel@tonic-gate }
415*0Sstevel@tonic-gate 
416*0Sstevel@tonic-gate struct interface *
417*0Sstevel@tonic-gate findremoteif(in_addr_t addr)
418*0Sstevel@tonic-gate {
419*0Sstevel@tonic-gate 	struct interface *ifp;
420*0Sstevel@tonic-gate 
421*0Sstevel@tonic-gate 	for (ifp = HFIRST(&ahash_tbl, &addr); ifp != NULL;
422*0Sstevel@tonic-gate 	    ifp = ifp->int_ahash.hl_next) {
423*0Sstevel@tonic-gate 		if ((ifp->int_state & IS_REMOTE) && ifp->int_addr == addr)
424*0Sstevel@tonic-gate 			return (ifp);
425*0Sstevel@tonic-gate 	}
426*0Sstevel@tonic-gate 
427*0Sstevel@tonic-gate 	return (NULL);
428*0Sstevel@tonic-gate }
429*0Sstevel@tonic-gate 
430*0Sstevel@tonic-gate struct interface *
431*0Sstevel@tonic-gate findifaddr(in_addr_t addr)
432*0Sstevel@tonic-gate {
433*0Sstevel@tonic-gate 	struct interface *ifp;
434*0Sstevel@tonic-gate 
435*0Sstevel@tonic-gate 	for (ifp = HFIRST(&ahash_tbl, &addr); ifp != NULL;
436*0Sstevel@tonic-gate 	    ifp = ifp->int_ahash.hl_next) {
437*0Sstevel@tonic-gate 		if (ifp->int_addr == addr)
438*0Sstevel@tonic-gate 			return (ifp);
439*0Sstevel@tonic-gate 	}
440*0Sstevel@tonic-gate 
441*0Sstevel@tonic-gate 	return (NULL);
442*0Sstevel@tonic-gate }
443*0Sstevel@tonic-gate 
444*0Sstevel@tonic-gate /*
445*0Sstevel@tonic-gate  * Return the first interface with the given index.
446*0Sstevel@tonic-gate  */
447*0Sstevel@tonic-gate struct interface *
448*0Sstevel@tonic-gate ifwithindex(ulong_t index,
449*0Sstevel@tonic-gate     boolean_t rescan_ok)
450*0Sstevel@tonic-gate {
451*0Sstevel@tonic-gate 	struct physical_interface *phyi;
452*0Sstevel@tonic-gate 
453*0Sstevel@tonic-gate 	for (;;) {
454*0Sstevel@tonic-gate 		for (phyi = HFIRST(&ihash_tbl, &index); phyi != NULL;
455*0Sstevel@tonic-gate 		    phyi = phyi->phyi_link.hl_next) {
456*0Sstevel@tonic-gate 			if (phyi->phyi_index == index)
457*0Sstevel@tonic-gate 				return (phyi->phyi_interface);
458*0Sstevel@tonic-gate 		}
459*0Sstevel@tonic-gate 
460*0Sstevel@tonic-gate 		/*
461*0Sstevel@tonic-gate 		 * If there is no known interface, maybe there is a
462*0Sstevel@tonic-gate 		 * new interface.  So just once look for new interfaces.
463*0Sstevel@tonic-gate 		 */
464*0Sstevel@tonic-gate 		if (!rescan_ok || IF_RESCAN_DELAY())
465*0Sstevel@tonic-gate 			return (NULL);
466*0Sstevel@tonic-gate 		rescan_ok = _B_FALSE;
467*0Sstevel@tonic-gate 		ifscan();
468*0Sstevel@tonic-gate 	}
469*0Sstevel@tonic-gate }
470*0Sstevel@tonic-gate 
471*0Sstevel@tonic-gate 
472*0Sstevel@tonic-gate /*
473*0Sstevel@tonic-gate  * Find an interface which should be receiving packets sent from the
474*0Sstevel@tonic-gate  * given address.  Used as a last ditch effort for figuring out which
475*0Sstevel@tonic-gate  * interface a packet came in on.  Also used for finding out which
476*0Sstevel@tonic-gate  * interface points towards the gateway of static routes learned from
477*0Sstevel@tonic-gate  * the kernel.
478*0Sstevel@tonic-gate  */
479*0Sstevel@tonic-gate struct interface *
480*0Sstevel@tonic-gate iflookup(in_addr_t addr)
481*0Sstevel@tonic-gate {
482*0Sstevel@tonic-gate 	struct interface *ifp, *maybe;
483*0Sstevel@tonic-gate 
484*0Sstevel@tonic-gate 	maybe = NULL;
485*0Sstevel@tonic-gate 	for (;;) {
486*0Sstevel@tonic-gate 		for (ifp = ifnet; ifp != NULL; ifp = ifp->int_next) {
487*0Sstevel@tonic-gate 			/*
488*0Sstevel@tonic-gate 			 * Don't return a duplicate interface since
489*0Sstevel@tonic-gate 			 * it is unusable for output.
490*0Sstevel@tonic-gate 			 */
491*0Sstevel@tonic-gate 			if (ifp->int_state & IS_DUP)
492*0Sstevel@tonic-gate 				continue;
493*0Sstevel@tonic-gate 
494*0Sstevel@tonic-gate 			if (ifp->int_if_flags & IFF_POINTOPOINT) {
495*0Sstevel@tonic-gate 				/* finished with a match */
496*0Sstevel@tonic-gate 				if (ifp->int_dstaddr == addr)
497*0Sstevel@tonic-gate 					return (ifp);
498*0Sstevel@tonic-gate 			} else {
499*0Sstevel@tonic-gate 				/* finished with an exact match */
500*0Sstevel@tonic-gate 				if (ifp->int_addr == addr) {
501*0Sstevel@tonic-gate 					if (IS_PASSIVE_IFP(ifp))
502*0Sstevel@tonic-gate 						trace_misc("iflookup "
503*0Sstevel@tonic-gate 						    "returning passive intf %s",
504*0Sstevel@tonic-gate 						    ifp->int_name);
505*0Sstevel@tonic-gate 					return (ifp);
506*0Sstevel@tonic-gate 				}
507*0Sstevel@tonic-gate 
508*0Sstevel@tonic-gate 				/* Look for the longest approximate match. */
509*0Sstevel@tonic-gate 				if (on_net(addr, ifp->int_net, ifp->int_mask) &&
510*0Sstevel@tonic-gate 				    (maybe == NULL ||
511*0Sstevel@tonic-gate 					ifp->int_mask > maybe->int_mask))
512*0Sstevel@tonic-gate 					maybe = ifp;
513*0Sstevel@tonic-gate 			}
514*0Sstevel@tonic-gate 		}
515*0Sstevel@tonic-gate 
516*0Sstevel@tonic-gate 		/*
517*0Sstevel@tonic-gate 		 * If there is no known interface, maybe there is a
518*0Sstevel@tonic-gate 		 * new interface.  So just once look for new interfaces.
519*0Sstevel@tonic-gate 		 */
520*0Sstevel@tonic-gate 		if (maybe == NULL && !IF_RESCAN_DELAY())
521*0Sstevel@tonic-gate 			ifscan();
522*0Sstevel@tonic-gate 		else
523*0Sstevel@tonic-gate 			break;
524*0Sstevel@tonic-gate 	}
525*0Sstevel@tonic-gate 
526*0Sstevel@tonic-gate 	if (maybe != NULL && IS_PASSIVE_IFP(maybe)) {
527*0Sstevel@tonic-gate 		trace_misc("iflookup returning passive intf %s",
528*0Sstevel@tonic-gate 		    maybe->int_name);
529*0Sstevel@tonic-gate 	}
530*0Sstevel@tonic-gate 	return (maybe);
531*0Sstevel@tonic-gate }
532*0Sstevel@tonic-gate 
533*0Sstevel@tonic-gate /*
534*0Sstevel@tonic-gate  * Find the netmask that would be inferred by RIPv1 listeners
535*0Sstevel@tonic-gate  *	on the given interface for a given network.
536*0Sstevel@tonic-gate  *	If no interface is specified, look for the best fitting	interface.
537*0Sstevel@tonic-gate  */
538*0Sstevel@tonic-gate in_addr_t
539*0Sstevel@tonic-gate ripv1_mask_net(in_addr_t addr,	/* in network byte order */
540*0Sstevel@tonic-gate     const struct interface *ifp)	/* as seen on this interface */
541*0Sstevel@tonic-gate {
542*0Sstevel@tonic-gate 	const struct r1net *r1p;
543*0Sstevel@tonic-gate 	in_addr_t mask = 0;
544*0Sstevel@tonic-gate 
545*0Sstevel@tonic-gate 	if (addr == 0)			/* default always has 0 mask */
546*0Sstevel@tonic-gate 		return (mask);
547*0Sstevel@tonic-gate 
548*0Sstevel@tonic-gate 	if (ifp != NULL && ifp->int_ripv1_mask != HOST_MASK) {
549*0Sstevel@tonic-gate 		/*
550*0Sstevel@tonic-gate 		 * If the target network is that of the associated interface
551*0Sstevel@tonic-gate 		 * on which it arrived, then use the netmask of the interface.
552*0Sstevel@tonic-gate 		 */
553*0Sstevel@tonic-gate 		if (on_net(addr, ifp->int_net, ifp->int_std_mask))
554*0Sstevel@tonic-gate 			mask = ifp->int_ripv1_mask;
555*0Sstevel@tonic-gate 
556*0Sstevel@tonic-gate 	} else {
557*0Sstevel@tonic-gate 		/*
558*0Sstevel@tonic-gate 		 * Examine all interfaces, and if it the target seems
559*0Sstevel@tonic-gate 		 * to have the same network number of an interface, use the
560*0Sstevel@tonic-gate 		 * netmask of that interface.  If there is more than one
561*0Sstevel@tonic-gate 		 * such interface, prefer the interface with the longest
562*0Sstevel@tonic-gate 		 * match.
563*0Sstevel@tonic-gate 		 */
564*0Sstevel@tonic-gate 		for (ifp = ifnet; ifp != NULL; ifp = ifp->int_next) {
565*0Sstevel@tonic-gate 			if (on_net(addr, ifp->int_std_net, ifp->int_std_mask) &&
566*0Sstevel@tonic-gate 			    ifp->int_ripv1_mask > mask &&
567*0Sstevel@tonic-gate 			    ifp->int_ripv1_mask != HOST_MASK)
568*0Sstevel@tonic-gate 				mask = ifp->int_ripv1_mask;
569*0Sstevel@tonic-gate 		}
570*0Sstevel@tonic-gate 
571*0Sstevel@tonic-gate 	}
572*0Sstevel@tonic-gate 
573*0Sstevel@tonic-gate 	if (mask == 0) {
574*0Sstevel@tonic-gate 		/*
575*0Sstevel@tonic-gate 		 * Check to see if the user has supplied an applicable
576*0Sstevel@tonic-gate 		 * netmask as a ripv1_mask option in /etc/gateways.
577*0Sstevel@tonic-gate 		 */
578*0Sstevel@tonic-gate 		for (r1p = r1nets; r1p != NULL; r1p = r1p->r1net_next) {
579*0Sstevel@tonic-gate 			/*
580*0Sstevel@tonic-gate 			 * If the address is is on a matching network
581*0Sstevel@tonic-gate 			 * and we haven't already found a longer match,
582*0Sstevel@tonic-gate 			 * use the matching netmask.
583*0Sstevel@tonic-gate 			 */
584*0Sstevel@tonic-gate 			if (on_net(addr, r1p->r1net_net, r1p->r1net_match) &&
585*0Sstevel@tonic-gate 			    r1p->r1net_mask > mask)
586*0Sstevel@tonic-gate 				mask = r1p->r1net_mask;
587*0Sstevel@tonic-gate 		}
588*0Sstevel@tonic-gate 
589*0Sstevel@tonic-gate 		/* Otherwise, make the classic A/B/C guess. */
590*0Sstevel@tonic-gate 		if (mask == 0)
591*0Sstevel@tonic-gate 			mask = std_mask(addr);
592*0Sstevel@tonic-gate 	}
593*0Sstevel@tonic-gate 
594*0Sstevel@tonic-gate 	return (mask);
595*0Sstevel@tonic-gate }
596*0Sstevel@tonic-gate 
597*0Sstevel@tonic-gate 
598*0Sstevel@tonic-gate in_addr_t
599*0Sstevel@tonic-gate ripv1_mask_host(in_addr_t addr,		/* in network byte order */
600*0Sstevel@tonic-gate     const struct interface *ifp)	/* as seen on this interface */
601*0Sstevel@tonic-gate {
602*0Sstevel@tonic-gate 	in_addr_t mask = ripv1_mask_net(addr, ifp);
603*0Sstevel@tonic-gate 
604*0Sstevel@tonic-gate 
605*0Sstevel@tonic-gate 	/*
606*0Sstevel@tonic-gate 	 * If the computed netmask does not mask all of the set bits
607*0Sstevel@tonic-gate 	 * in the address, then assume it is a host address
608*0Sstevel@tonic-gate 	 */
609*0Sstevel@tonic-gate 	if ((ntohl(addr) & ~mask) != 0)
610*0Sstevel@tonic-gate 		mask = HOST_MASK;
611*0Sstevel@tonic-gate 	return (mask);
612*0Sstevel@tonic-gate }
613*0Sstevel@tonic-gate 
614*0Sstevel@tonic-gate 
615*0Sstevel@tonic-gate /* See if a IP address looks reasonable as a destination */
616*0Sstevel@tonic-gate boolean_t			/* _B_FALSE=bad _B_TRUE=good */
617*0Sstevel@tonic-gate check_dst(in_addr_t addr)
618*0Sstevel@tonic-gate {
619*0Sstevel@tonic-gate 	addr = ntohl(addr);
620*0Sstevel@tonic-gate 
621*0Sstevel@tonic-gate 	if (IN_CLASSA(addr)) {
622*0Sstevel@tonic-gate 		if (addr == 0)
623*0Sstevel@tonic-gate 			return (_B_TRUE);	/* default */
624*0Sstevel@tonic-gate 
625*0Sstevel@tonic-gate 		addr >>= IN_CLASSA_NSHIFT;
626*0Sstevel@tonic-gate 		return (addr != 0 && addr != IN_LOOPBACKNET);
627*0Sstevel@tonic-gate 	}
628*0Sstevel@tonic-gate 
629*0Sstevel@tonic-gate 	return (IN_CLASSB(addr) || IN_CLASSC(addr));
630*0Sstevel@tonic-gate }
631*0Sstevel@tonic-gate 
632*0Sstevel@tonic-gate /*
633*0Sstevel@tonic-gate  * Find an existing interface which has the given parameters, but don't
634*0Sstevel@tonic-gate  * return the interface with name "name" if "name" is specified.
635*0Sstevel@tonic-gate  */
636*0Sstevel@tonic-gate struct interface *
637*0Sstevel@tonic-gate check_dup(const char *name,	/* Don't return this interface */
638*0Sstevel@tonic-gate     in_addr_t addr,	/* IP address, so network byte order */
639*0Sstevel@tonic-gate     in_addr_t dstaddr,	/* ditto */
640*0Sstevel@tonic-gate     in_addr_t mask,	/* mask, so host byte order */
641*0Sstevel@tonic-gate     int if_flags,	/* set IFF_POINTOPOINT to ignore local int_addr */
642*0Sstevel@tonic-gate     boolean_t allowdups)	/* set true to include duplicates */
643*0Sstevel@tonic-gate {
644*0Sstevel@tonic-gate 	struct interface *best_ifp = NULL;
645*0Sstevel@tonic-gate 	struct interface *ifp;
646*0Sstevel@tonic-gate 	in_addr_t dstaddr_h = ntohl(dstaddr);
647*0Sstevel@tonic-gate 	int best_pref = 0;
648*0Sstevel@tonic-gate 	int pref;
649*0Sstevel@tonic-gate 
650*0Sstevel@tonic-gate 	for (ifp = ifnet; ifp != NULL; ifp = ifp->int_next) {
651*0Sstevel@tonic-gate 		/* This interface, not a duplicate. */
652*0Sstevel@tonic-gate 		if (name != NULL && strcmp(name, ifp->int_name) == 0)
653*0Sstevel@tonic-gate 			continue;
654*0Sstevel@tonic-gate 
655*0Sstevel@tonic-gate 		/*
656*0Sstevel@tonic-gate 		 * Find an interface which isn't already a duplicate to
657*0Sstevel@tonic-gate 		 * avoid cyclical duplication.  (i.e. qfe0:1 is a duplicate
658*0Sstevel@tonic-gate 		 * of qfe0, and qfe0 is a duplicate of qfe0:1.  That would
659*0Sstevel@tonic-gate 		 * be bad)
660*0Sstevel@tonic-gate 		 */
661*0Sstevel@tonic-gate 		if (!allowdups && (ifp->int_state & IS_DUP))
662*0Sstevel@tonic-gate 			continue;
663*0Sstevel@tonic-gate 
664*0Sstevel@tonic-gate 		if (ifp->int_mask != mask)
665*0Sstevel@tonic-gate 			continue;
666*0Sstevel@tonic-gate 
667*0Sstevel@tonic-gate 		if (!IS_IFF_UP(ifp->int_if_flags))
668*0Sstevel@tonic-gate 			continue;
669*0Sstevel@tonic-gate 
670*0Sstevel@tonic-gate 		/*
671*0Sstevel@tonic-gate 		 * The local address can only be shared with a point-to-point
672*0Sstevel@tonic-gate 		 * link.
673*0Sstevel@tonic-gate 		 */
674*0Sstevel@tonic-gate 		if ((ifp->int_addr == addr &&
675*0Sstevel@tonic-gate 		    ((if_flags|ifp->int_if_flags) & IFF_POINTOPOINT) == 0) ||
676*0Sstevel@tonic-gate 		    on_net(ifp->int_dstaddr, dstaddr_h, mask)) {
677*0Sstevel@tonic-gate 			pref = 0;
678*0Sstevel@tonic-gate 			if (!(ifp->int_state & IS_ALIAS))
679*0Sstevel@tonic-gate 				pref++;
680*0Sstevel@tonic-gate 			if (!IS_RIP_OUT_OFF(ifp->int_state))
681*0Sstevel@tonic-gate 				pref += 2;
682*0Sstevel@tonic-gate 			if (IS_IFF_ROUTING(ifp->int_if_flags))
683*0Sstevel@tonic-gate 				pref += 4;
684*0Sstevel@tonic-gate 			if (pref > best_pref) {
685*0Sstevel@tonic-gate 				best_pref = pref;
686*0Sstevel@tonic-gate 				best_ifp = ifp;
687*0Sstevel@tonic-gate 			}
688*0Sstevel@tonic-gate 		}
689*0Sstevel@tonic-gate 	}
690*0Sstevel@tonic-gate 	return (best_ifp);
691*0Sstevel@tonic-gate }
692*0Sstevel@tonic-gate 
693*0Sstevel@tonic-gate 
694*0Sstevel@tonic-gate /*
695*0Sstevel@tonic-gate  * See that a remote gateway is reachable.
696*0Sstevel@tonic-gate  *	Note that the answer can change as real interfaces come and go.
697*0Sstevel@tonic-gate  */
698*0Sstevel@tonic-gate boolean_t			/* _B_FALSE=bad _B_TRUE=good */
699*0Sstevel@tonic-gate check_remote(struct interface *ifp)
700*0Sstevel@tonic-gate {
701*0Sstevel@tonic-gate 	struct rt_entry *rt;
702*0Sstevel@tonic-gate 
703*0Sstevel@tonic-gate 	/* do not worry about other kinds */
704*0Sstevel@tonic-gate 	if (!(ifp->int_state & IS_REMOTE))
705*0Sstevel@tonic-gate 	    return (_B_TRUE);
706*0Sstevel@tonic-gate 
707*0Sstevel@tonic-gate 	rt = rtfind(ifp->int_addr);
708*0Sstevel@tonic-gate 	if (rt != NULL &&
709*0Sstevel@tonic-gate 	    rt->rt_ifp != NULL &&
710*0Sstevel@tonic-gate 	    on_net(ifp->int_addr,
711*0Sstevel@tonic-gate 		rt->rt_ifp->int_net, rt->rt_ifp->int_mask))
712*0Sstevel@tonic-gate 		return (_B_TRUE);
713*0Sstevel@tonic-gate 
714*0Sstevel@tonic-gate 	/*
715*0Sstevel@tonic-gate 	 * the gateway cannot be reached directly from one of our
716*0Sstevel@tonic-gate 	 * interfaces
717*0Sstevel@tonic-gate 	 */
718*0Sstevel@tonic-gate 	if (!(ifp->int_state & IS_BROKE)) {
719*0Sstevel@tonic-gate 		msglog("unreachable gateway %s in "PATH_GATEWAYS,
720*0Sstevel@tonic-gate 		    naddr_ntoa(ifp->int_addr));
721*0Sstevel@tonic-gate 		if_bad(ifp, _B_FALSE);
722*0Sstevel@tonic-gate 	}
723*0Sstevel@tonic-gate 	return (_B_FALSE);
724*0Sstevel@tonic-gate }
725*0Sstevel@tonic-gate 
726*0Sstevel@tonic-gate /* Delete an interface. */
727*0Sstevel@tonic-gate static void
728*0Sstevel@tonic-gate ifdel(struct interface *ifp)
729*0Sstevel@tonic-gate {
730*0Sstevel@tonic-gate 	struct rewire_data wire;
731*0Sstevel@tonic-gate 	boolean_t resurrected;
732*0Sstevel@tonic-gate 	struct physical_interface *phyi;
733*0Sstevel@tonic-gate 
734*0Sstevel@tonic-gate 	trace_if("Del", ifp);
735*0Sstevel@tonic-gate 
736*0Sstevel@tonic-gate 	ifp->int_state |= IS_BROKE;
737*0Sstevel@tonic-gate 
738*0Sstevel@tonic-gate 	/* unlink the interface */
739*0Sstevel@tonic-gate 	link_out(ifp, offsetof(struct interface, int_link));
740*0Sstevel@tonic-gate 	hash_unlink(&ahash_tbl, ifp);
741*0Sstevel@tonic-gate 	hash_unlink(&nhash_tbl, ifp);
742*0Sstevel@tonic-gate 	if (ifp->int_if_flags & IFF_BROADCAST)
743*0Sstevel@tonic-gate 		hash_unlink(&bhash_tbl, ifp);
744*0Sstevel@tonic-gate 
745*0Sstevel@tonic-gate 	/* Remove from list of interfaces with this ifIndex */
746*0Sstevel@tonic-gate 	if ((phyi = ifp->int_phys) != NULL) {
747*0Sstevel@tonic-gate 		link_out(ifp, offsetof(struct interface, int_ilist));
748*0Sstevel@tonic-gate 		if (phyi->phyi_interface == NULL) {
749*0Sstevel@tonic-gate 			hash_unlink(&ihash_tbl, phyi);
750*0Sstevel@tonic-gate 			free(phyi);
751*0Sstevel@tonic-gate 		}
752*0Sstevel@tonic-gate 	}
753*0Sstevel@tonic-gate 
754*0Sstevel@tonic-gate 	/*
755*0Sstevel@tonic-gate 	 * If this is a lead interface, then check first for
756*0Sstevel@tonic-gate 	 * duplicates of this interface with an eye towards promoting
757*0Sstevel@tonic-gate 	 * one of them.
758*0Sstevel@tonic-gate 	 */
759*0Sstevel@tonic-gate 	resurrected = _B_FALSE;
760*0Sstevel@tonic-gate 	if (!(ifp->int_state & IS_DUP) &&
761*0Sstevel@tonic-gate 	    (wire.if_new = check_dup(ifp->int_name, ifp->int_addr,
762*0Sstevel@tonic-gate 		ifp->int_dstaddr, ifp->int_mask, ifp->int_if_flags,
763*0Sstevel@tonic-gate 		_B_TRUE)) != NULL &&
764*0Sstevel@tonic-gate 	    !IS_IFF_QUIET(wire.if_new->int_if_flags)) {
765*0Sstevel@tonic-gate 
766*0Sstevel@tonic-gate 		trace_act("promoting duplicate %s in place of %s",
767*0Sstevel@tonic-gate 		    wire.if_new->int_name, ifp->int_name);
768*0Sstevel@tonic-gate 
769*0Sstevel@tonic-gate 		/* Rewire routes with the replacement interface */
770*0Sstevel@tonic-gate 		wire.if_old = ifp;
771*0Sstevel@tonic-gate 		wire.metric_delta = wire.if_new->int_metric - ifp->int_metric;
772*0Sstevel@tonic-gate 		(void) rn_walktree(rhead, walk_rewire, &wire);
773*0Sstevel@tonic-gate 		kern_rewire_ifp(wire.if_old, wire.if_new);
774*0Sstevel@tonic-gate 		if_rewire_rdisc(wire.if_old, wire.if_new);
775*0Sstevel@tonic-gate 
776*0Sstevel@tonic-gate 		/* Mark the replacement as being no longer a duplicate */
777*0Sstevel@tonic-gate 		wire.if_new->int_state &= ~IS_DUP;
778*0Sstevel@tonic-gate 		tot_interfaces++;
779*0Sstevel@tonic-gate 		if (!IS_RIP_OFF(wire.if_new->int_state))
780*0Sstevel@tonic-gate 			rip_interfaces++;
781*0Sstevel@tonic-gate 		if (!IS_RIP_OUT_OFF(wire.if_new->int_state))
782*0Sstevel@tonic-gate 			ripout_interfaces++;
783*0Sstevel@tonic-gate 		if (IS_IFF_ROUTING(wire.if_new->int_if_flags))
784*0Sstevel@tonic-gate 			fwd_interfaces++;
785*0Sstevel@tonic-gate 
786*0Sstevel@tonic-gate 		set_rdisc_mg(wire.if_new, 1);
787*0Sstevel@tonic-gate 		rip_mcast_on(wire.if_new);
788*0Sstevel@tonic-gate 
789*0Sstevel@tonic-gate 		/* We came out ok; no need to clobber routes over this. */
790*0Sstevel@tonic-gate 		resurrected = _B_TRUE;
791*0Sstevel@tonic-gate 	}
792*0Sstevel@tonic-gate 
793*0Sstevel@tonic-gate 	rip_mcast_off(ifp);
794*0Sstevel@tonic-gate 	if (rip_sock_interface == ifp)
795*0Sstevel@tonic-gate 		rip_sock_interface = NULL;
796*0Sstevel@tonic-gate 
797*0Sstevel@tonic-gate 	set_rdisc_mg(ifp, 0);
798*0Sstevel@tonic-gate 
799*0Sstevel@tonic-gate 	/*
800*0Sstevel@tonic-gate 	 * Note that duplicates are not counted in the total number of
801*0Sstevel@tonic-gate 	 * interfaces.
802*0Sstevel@tonic-gate 	 */
803*0Sstevel@tonic-gate 	if (!(ifp->int_state & IS_DUP) && !IS_IFF_QUIET(ifp->int_if_flags)) {
804*0Sstevel@tonic-gate 		tot_interfaces--;
805*0Sstevel@tonic-gate 		if (!IS_RIP_OFF(ifp->int_state))
806*0Sstevel@tonic-gate 			rip_interfaces--;
807*0Sstevel@tonic-gate 		if (!IS_RIP_OUT_OFF(ifp->int_state))
808*0Sstevel@tonic-gate 			ripout_interfaces--;
809*0Sstevel@tonic-gate 		if (IS_IFF_ROUTING(ifp->int_if_flags))
810*0Sstevel@tonic-gate 			fwd_interfaces--;
811*0Sstevel@tonic-gate 	}
812*0Sstevel@tonic-gate 
813*0Sstevel@tonic-gate 	if (!resurrected) {
814*0Sstevel@tonic-gate 		/*
815*0Sstevel@tonic-gate 		 * Zap all routes associated with this interface.
816*0Sstevel@tonic-gate 		 * Assume routes just using gateways beyond this interface
817*0Sstevel@tonic-gate 		 * will timeout naturally, and have probably already died.
818*0Sstevel@tonic-gate 		 */
819*0Sstevel@tonic-gate 		(void) rn_walktree(rhead, walk_bad, ifp);
820*0Sstevel@tonic-gate 		kern_flush_ifp(ifp);
821*0Sstevel@tonic-gate 
822*0Sstevel@tonic-gate 		if_bad_rdisc(ifp);
823*0Sstevel@tonic-gate 	}
824*0Sstevel@tonic-gate 
825*0Sstevel@tonic-gate 	free(ifp);
826*0Sstevel@tonic-gate }
827*0Sstevel@tonic-gate 
828*0Sstevel@tonic-gate 
829*0Sstevel@tonic-gate /* Mark an interface ill. */
830*0Sstevel@tonic-gate void
831*0Sstevel@tonic-gate if_sick(struct interface *ifp, boolean_t recurse)
832*0Sstevel@tonic-gate {
833*0Sstevel@tonic-gate 	struct interface *ifp1;
834*0Sstevel@tonic-gate 
835*0Sstevel@tonic-gate 	if (0 == (ifp->int_state & (IS_SICK | IS_BROKE))) {
836*0Sstevel@tonic-gate 		ifp->int_state |= IS_SICK;
837*0Sstevel@tonic-gate 		ifp->int_act_time = NEVER;
838*0Sstevel@tonic-gate 		trace_if("Chg", ifp);
839*0Sstevel@tonic-gate 
840*0Sstevel@tonic-gate 		LIM_SEC(ifscan_timer, now.tv_sec+CHECK_BAD_INTERVAL);
841*0Sstevel@tonic-gate 		if (recurse && ifp->int_phys != NULL) {
842*0Sstevel@tonic-gate 			/* If an interface is sick, so are its aliases. */
843*0Sstevel@tonic-gate 			for (ifp1 = ifp->int_phys->phyi_interface;
844*0Sstevel@tonic-gate 			    ifp1 != NULL; ifp1 = ifp1->int_ilist.hl_next) {
845*0Sstevel@tonic-gate 				if (ifp1 != ifp)
846*0Sstevel@tonic-gate 					if_sick(ifp1, _B_FALSE);
847*0Sstevel@tonic-gate 			}
848*0Sstevel@tonic-gate 		}
849*0Sstevel@tonic-gate 	}
850*0Sstevel@tonic-gate }
851*0Sstevel@tonic-gate 
852*0Sstevel@tonic-gate 
853*0Sstevel@tonic-gate /* Mark an interface dead. */
854*0Sstevel@tonic-gate static void
855*0Sstevel@tonic-gate if_bad(struct interface *ifp, boolean_t recurse)
856*0Sstevel@tonic-gate {
857*0Sstevel@tonic-gate 	struct interface *ifp1;
858*0Sstevel@tonic-gate 	struct rewire_data wire;
859*0Sstevel@tonic-gate 
860*0Sstevel@tonic-gate 	if (ifp->int_state & IS_BROKE)
861*0Sstevel@tonic-gate 		return;
862*0Sstevel@tonic-gate 
863*0Sstevel@tonic-gate 	LIM_SEC(ifscan_timer, now.tv_sec+CHECK_BAD_INTERVAL);
864*0Sstevel@tonic-gate 
865*0Sstevel@tonic-gate 	ifp->int_state |= (IS_BROKE | IS_SICK);
866*0Sstevel@tonic-gate 	ifp->int_act_time = NEVER;
867*0Sstevel@tonic-gate 	ifp->int_query_time = NEVER;
868*0Sstevel@tonic-gate 	/* Note: don't reset the stats timestamp here */
869*0Sstevel@tonic-gate 
870*0Sstevel@tonic-gate 	trace_if("Chg", ifp);
871*0Sstevel@tonic-gate 
872*0Sstevel@tonic-gate 	if (recurse && ifp->int_phys != NULL) {
873*0Sstevel@tonic-gate 		/* If an interface is bad, so are its aliases. */
874*0Sstevel@tonic-gate 		for (ifp1 = ifp->int_phys->phyi_interface;
875*0Sstevel@tonic-gate 		    ifp1 != NULL; ifp1 = ifp1->int_ilist.hl_next) {
876*0Sstevel@tonic-gate 			if (ifp1 != ifp)
877*0Sstevel@tonic-gate 				if_bad(ifp1, _B_FALSE);
878*0Sstevel@tonic-gate 		}
879*0Sstevel@tonic-gate 	}
880*0Sstevel@tonic-gate 
881*0Sstevel@tonic-gate 	/* If we can find a replacement, then pick it up. */
882*0Sstevel@tonic-gate 	if (!(ifp->int_state & IS_DUP) &&
883*0Sstevel@tonic-gate 	    (wire.if_new = check_dup(ifp->int_name, ifp->int_addr,
884*0Sstevel@tonic-gate 		ifp->int_dstaddr, ifp->int_mask, ifp->int_if_flags,
885*0Sstevel@tonic-gate 		_B_TRUE)) != NULL &&
886*0Sstevel@tonic-gate 	    !IS_IFF_QUIET(wire.if_new->int_if_flags)) {
887*0Sstevel@tonic-gate 		trace_act("promoting duplicate %s in place of %s",
888*0Sstevel@tonic-gate 		    wire.if_new->int_name, ifp->int_name);
889*0Sstevel@tonic-gate 		wire.if_old = ifp;
890*0Sstevel@tonic-gate 		wire.metric_delta = wire.if_new->int_metric - ifp->int_metric;
891*0Sstevel@tonic-gate 		(void) rn_walktree(rhead, walk_rewire, &wire);
892*0Sstevel@tonic-gate 		if_rewire_rdisc(wire.if_old, wire.if_new);
893*0Sstevel@tonic-gate 
894*0Sstevel@tonic-gate 		/* The broken guy becomes the duplicate */
895*0Sstevel@tonic-gate 		wire.if_new->int_state &= ~IS_DUP;
896*0Sstevel@tonic-gate 		set_rdisc_mg(ifp, 0);
897*0Sstevel@tonic-gate 		rip_mcast_off(ifp);
898*0Sstevel@tonic-gate 		ifp->int_state |= IS_DUP;
899*0Sstevel@tonic-gate 
900*0Sstevel@tonic-gate 		/* join the mcast groups for the replacement */
901*0Sstevel@tonic-gate 		set_rdisc_mg(wire.if_new, 1);
902*0Sstevel@tonic-gate 		rip_mcast_on(wire.if_new);
903*0Sstevel@tonic-gate 
904*0Sstevel@tonic-gate 		if (rip_sock_interface == ifp)
905*0Sstevel@tonic-gate 			rip_sock_interface = NULL;
906*0Sstevel@tonic-gate 	} else {
907*0Sstevel@tonic-gate 		(void) rn_walktree(rhead, walk_bad, ifp);
908*0Sstevel@tonic-gate 		if_bad_rdisc(ifp);
909*0Sstevel@tonic-gate 	}
910*0Sstevel@tonic-gate }
911*0Sstevel@tonic-gate 
912*0Sstevel@tonic-gate 
913*0Sstevel@tonic-gate /* Mark an interface alive */
914*0Sstevel@tonic-gate void
915*0Sstevel@tonic-gate if_ok(struct interface *ifp, const char *type, boolean_t recurse)
916*0Sstevel@tonic-gate {
917*0Sstevel@tonic-gate 	struct interface *ifp1;
918*0Sstevel@tonic-gate 	boolean_t wasbroken = _B_FALSE;
919*0Sstevel@tonic-gate 
920*0Sstevel@tonic-gate 	if (ifp->int_state & IS_BROKE) {
921*0Sstevel@tonic-gate 		writelog(LOG_WARNING, "%sinterface %s to %s restored",
922*0Sstevel@tonic-gate 		    type, ifp->int_name, naddr_ntoa(ifp->int_dstaddr));
923*0Sstevel@tonic-gate 		ifp->int_state &= ~(IS_BROKE | IS_SICK);
924*0Sstevel@tonic-gate 		wasbroken = _B_TRUE;
925*0Sstevel@tonic-gate 	} else if (ifp->int_state & IS_SICK) {
926*0Sstevel@tonic-gate 		trace_act("%sinterface %s to %s working better",
927*0Sstevel@tonic-gate 		    type, ifp->int_name, naddr_ntoa(ifp->int_dstaddr));
928*0Sstevel@tonic-gate 		ifp->int_state &= ~IS_SICK;
929*0Sstevel@tonic-gate 	}
930*0Sstevel@tonic-gate 
931*0Sstevel@tonic-gate 	if (recurse && ifp->int_phys != NULL && IS_IFF_UP(ifp->int_if_flags)) {
932*0Sstevel@tonic-gate 		ifp->int_phys->phyi_data.ts = 0;
933*0Sstevel@tonic-gate 
934*0Sstevel@tonic-gate 		/* Also mark all aliases of this interface as ok */
935*0Sstevel@tonic-gate 		for (ifp1 = ifp->int_phys->phyi_interface;
936*0Sstevel@tonic-gate 		    ifp1 != NULL; ifp1 = ifp1->int_ilist.hl_next) {
937*0Sstevel@tonic-gate 			if (ifp1 != ifp)
938*0Sstevel@tonic-gate 				if_ok(ifp1, type, _B_FALSE);
939*0Sstevel@tonic-gate 		}
940*0Sstevel@tonic-gate 	}
941*0Sstevel@tonic-gate 
942*0Sstevel@tonic-gate 	if (wasbroken) {
943*0Sstevel@tonic-gate 		if (!(ifp->int_state & IS_DUP))
944*0Sstevel@tonic-gate 			if_ok_rdisc(ifp);
945*0Sstevel@tonic-gate 
946*0Sstevel@tonic-gate 		if (ifp->int_state & IS_REMOTE)
947*0Sstevel@tonic-gate 			(void) addrouteforif(ifp);
948*0Sstevel@tonic-gate 	}
949*0Sstevel@tonic-gate }
950*0Sstevel@tonic-gate 
951*0Sstevel@tonic-gate boolean_t
952*0Sstevel@tonic-gate remote_address_ok(struct interface *ifp, in_addr_t addr)
953*0Sstevel@tonic-gate {
954*0Sstevel@tonic-gate 	if (ifp->int_if_flags & IFF_POINTOPOINT) {
955*0Sstevel@tonic-gate 		if (addr == ifp->int_dstaddr)
956*0Sstevel@tonic-gate 			return (_B_TRUE);
957*0Sstevel@tonic-gate 	} else if (on_net(addr, ifp->int_net, ifp->int_mask)) {
958*0Sstevel@tonic-gate 		return (_B_TRUE);
959*0Sstevel@tonic-gate 	}
960*0Sstevel@tonic-gate 	return (_B_FALSE);
961*0Sstevel@tonic-gate }
962*0Sstevel@tonic-gate 
963*0Sstevel@tonic-gate /*
964*0Sstevel@tonic-gate  * Find the network interfaces which have configured themselves.
965*0Sstevel@tonic-gate  *	This must be done regularly, if only for extra addresses
966*0Sstevel@tonic-gate  *	that come and go on interfaces.
967*0Sstevel@tonic-gate  */
968*0Sstevel@tonic-gate void
969*0Sstevel@tonic-gate ifscan(void)
970*0Sstevel@tonic-gate {
971*0Sstevel@tonic-gate 	uint_t complaints = 0;
972*0Sstevel@tonic-gate 	static uint_t prev_complaints = 0;
973*0Sstevel@tonic-gate #define	COMP_BADADDR	0x001
974*0Sstevel@tonic-gate #define	COMP_NODST	0x002
975*0Sstevel@tonic-gate #define	COMP_NOBADDR	0x004
976*0Sstevel@tonic-gate #define	COMP_NOMASK	0x008
977*0Sstevel@tonic-gate #define	COMP_BAD_METRIC	0x010
978*0Sstevel@tonic-gate #define	COMP_NETMASK	0x020
979*0Sstevel@tonic-gate #define	COMP_NO_INDEX	0x040
980*0Sstevel@tonic-gate #define	COMP_BAD_FLAGS	0x080
981*0Sstevel@tonic-gate #define	COMP_NO_KSTATS	0x100
982*0Sstevel@tonic-gate #define	COMP_IPFORWARD	0x200
983*0Sstevel@tonic-gate 
984*0Sstevel@tonic-gate 	struct interface ifs, *ifp, *ifp1;
985*0Sstevel@tonic-gate 	struct rt_entry *rt;
986*0Sstevel@tonic-gate 	size_t needed;
987*0Sstevel@tonic-gate 	static size_t lastneeded = 0;
988*0Sstevel@tonic-gate 	char *buf;
989*0Sstevel@tonic-gate 	static char *lastbuf = NULL;
990*0Sstevel@tonic-gate 	int32_t in, ierr, out, oerr;
991*0Sstevel@tonic-gate 	struct intnet *intnetp;
992*0Sstevel@tonic-gate 	int sock;
993*0Sstevel@tonic-gate 	struct lifnum lifn;
994*0Sstevel@tonic-gate 	struct lifconf lifc;
995*0Sstevel@tonic-gate 	struct lifreq *lifrp, *lifrp_lim;
996*0Sstevel@tonic-gate 	struct sockaddr_in *sinp;
997*0Sstevel@tonic-gate 	in_addr_t haddr;
998*0Sstevel@tonic-gate 	static in_addr_t myaddr = 0;
999*0Sstevel@tonic-gate 	uint32_t ifindex;
1000*0Sstevel@tonic-gate 	struct phyi_data newstats;
1001*0Sstevel@tonic-gate 	struct physical_interface *phyi;
1002*0Sstevel@tonic-gate 
1003*0Sstevel@tonic-gate 	last_ifscan = now;
1004*0Sstevel@tonic-gate 	ifscan_timer.tv_sec = now.tv_sec +
1005*0Sstevel@tonic-gate 	    (supplier || tot_interfaces != 1 ?
1006*0Sstevel@tonic-gate 		CHECK_ACT_INTERVAL : CHECK_QUIET_INTERVAL);
1007*0Sstevel@tonic-gate 
1008*0Sstevel@tonic-gate 	/* mark all interfaces so we can get rid of those that disappear */
1009*0Sstevel@tonic-gate 	for (ifp = ifnet; ifp != NULL; ifp = ifp->int_next)
1010*0Sstevel@tonic-gate 		ifp->int_state &= ~IS_CHECKED;
1011*0Sstevel@tonic-gate 
1012*0Sstevel@tonic-gate 	/* Fetch the size of the current interface list */
1013*0Sstevel@tonic-gate 	if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
1014*0Sstevel@tonic-gate 		BADERR(_B_TRUE, "ifscan: socket(SOCK_DGRAM)");
1015*0Sstevel@tonic-gate 	lifn.lifn_family = AF_INET;	/* Only count IPv4 interfaces */
1016*0Sstevel@tonic-gate 	/*
1017*0Sstevel@tonic-gate 	 * Include IFF_NOXMIT interfaces.  Such interfaces are exluded
1018*0Sstevel@tonic-gate 	 * from protocol operations, but their inclusion in the
1019*0Sstevel@tonic-gate 	 * internal table enables us to know when packets arrive on
1020*0Sstevel@tonic-gate 	 * such interfaces.
1021*0Sstevel@tonic-gate 	 */
1022*0Sstevel@tonic-gate 	lifn.lifn_flags = LIFC_NOXMIT;
1023*0Sstevel@tonic-gate calculate_lifc_len:
1024*0Sstevel@tonic-gate 	if (ioctl(sock, SIOCGLIFNUM, &lifn) == -1) {
1025*0Sstevel@tonic-gate 		BADERR(_B_TRUE, "ifscan: ioctl(SIOCGLIFNUM)");
1026*0Sstevel@tonic-gate 	}
1027*0Sstevel@tonic-gate 
1028*0Sstevel@tonic-gate 	/*
1029*0Sstevel@tonic-gate 	 * When calculating the buffer size needed, add a small number
1030*0Sstevel@tonic-gate 	 * of interfaces to those we counted.  We do this to capture
1031*0Sstevel@tonic-gate 	 * the interface status of potential interfaces which may have
1032*0Sstevel@tonic-gate 	 * been plumbed between the SIOCGLIFNUM and the SIOCGLIFCONF.
1033*0Sstevel@tonic-gate 	 * Try to reuse the buffer we already have to avoid heap
1034*0Sstevel@tonic-gate 	 * thrash.
1035*0Sstevel@tonic-gate 	 */
1036*0Sstevel@tonic-gate 	needed = (lifn.lifn_count + 4) * sizeof (struct lifreq);
1037*0Sstevel@tonic-gate 	if (needed > lastneeded || needed < lastneeded/2) {
1038*0Sstevel@tonic-gate 		if (lastbuf != NULL)
1039*0Sstevel@tonic-gate 			free(lastbuf);
1040*0Sstevel@tonic-gate 		if ((buf = malloc(needed)) == NULL) {
1041*0Sstevel@tonic-gate 			lastbuf = NULL;
1042*0Sstevel@tonic-gate 			msglog("ifscan: malloc: %s", rip_strerror(errno));
1043*0Sstevel@tonic-gate 			return;
1044*0Sstevel@tonic-gate 		}
1045*0Sstevel@tonic-gate 	} else {
1046*0Sstevel@tonic-gate 		buf = lastbuf;
1047*0Sstevel@tonic-gate 	}
1048*0Sstevel@tonic-gate 	lastbuf = buf;
1049*0Sstevel@tonic-gate 	lastneeded = needed;
1050*0Sstevel@tonic-gate 
1051*0Sstevel@tonic-gate 	/* Get the list */
1052*0Sstevel@tonic-gate 	lifc.lifc_family = AF_INET;	/* We only need IPv4 interfaces */
1053*0Sstevel@tonic-gate 	lifc.lifc_flags = LIFC_NOXMIT;
1054*0Sstevel@tonic-gate 	lifc.lifc_len = needed;
1055*0Sstevel@tonic-gate 	lifc.lifc_buf = buf;
1056*0Sstevel@tonic-gate 	if (ioctl(sock, SIOCGLIFCONF, &lifc) == -1) {
1057*0Sstevel@tonic-gate 		/*
1058*0Sstevel@tonic-gate 		 * IP returns EINVAL if the lifc_len we passed in is
1059*0Sstevel@tonic-gate 		 * too small.  If that's the case, we need to go back
1060*0Sstevel@tonic-gate 		 * and recalculate it.
1061*0Sstevel@tonic-gate 		 */
1062*0Sstevel@tonic-gate 		if (errno == EINVAL)
1063*0Sstevel@tonic-gate 			goto calculate_lifc_len;
1064*0Sstevel@tonic-gate 		BADERR(_B_TRUE, "ifscan: ioctl(SIOCGLIFCONF)");
1065*0Sstevel@tonic-gate 	}
1066*0Sstevel@tonic-gate 
1067*0Sstevel@tonic-gate 	/*
1068*0Sstevel@tonic-gate 	 * If the returned lifc_len is within one lifreq of the
1069*0Sstevel@tonic-gate 	 * requested ammount, we may have used a buffer which
1070*0Sstevel@tonic-gate 	 * was too small to hold all of the interfaces.  In that
1071*0Sstevel@tonic-gate 	 * case go back and recalculate needed.
1072*0Sstevel@tonic-gate 	 */
1073*0Sstevel@tonic-gate 	if (lifc.lifc_len >= needed - sizeof (struct lifreq))
1074*0Sstevel@tonic-gate 		goto calculate_lifc_len;
1075*0Sstevel@tonic-gate 
1076*0Sstevel@tonic-gate 	lifrp = lifc.lifc_req;
1077*0Sstevel@tonic-gate 	lifrp_lim = lifrp + lifc.lifc_len / sizeof (*lifrp);
1078*0Sstevel@tonic-gate 	for (; lifrp < lifrp_lim; lifrp++) {
1079*0Sstevel@tonic-gate 
1080*0Sstevel@tonic-gate 		(void) memset(&ifs, 0, sizeof (ifs));
1081*0Sstevel@tonic-gate 
1082*0Sstevel@tonic-gate 		(void) strlcpy(ifs.int_name, lifrp->lifr_name,
1083*0Sstevel@tonic-gate 		    sizeof (ifs.int_name));
1084*0Sstevel@tonic-gate 
1085*0Sstevel@tonic-gate 		/* SIOCGLIFCONF fills in the lifr_addr of each lifreq */
1086*0Sstevel@tonic-gate 		ifs.int_addr = ((struct sockaddr_in *)&lifrp->lifr_addr)->
1087*0Sstevel@tonic-gate 		    sin_addr.s_addr;
1088*0Sstevel@tonic-gate 
1089*0Sstevel@tonic-gate 		if (ioctl(sock, SIOCGLIFFLAGS, lifrp) == -1) {
1090*0Sstevel@tonic-gate 			if (!(prev_complaints & COMP_BAD_FLAGS))
1091*0Sstevel@tonic-gate 				writelog(LOG_NOTICE,
1092*0Sstevel@tonic-gate 				    "unable to get interface flags for %s: %s",
1093*0Sstevel@tonic-gate 				    ifs.int_name, rip_strerror(errno));
1094*0Sstevel@tonic-gate 			complaints |= COMP_BAD_FLAGS;
1095*0Sstevel@tonic-gate 			ifs.int_if_flags = 0;
1096*0Sstevel@tonic-gate 		} else {
1097*0Sstevel@tonic-gate 			ifs.int_if_flags = lifrp->lifr_flags;
1098*0Sstevel@tonic-gate 		}
1099*0Sstevel@tonic-gate 
1100*0Sstevel@tonic-gate 		if (IN_EXPERIMENTAL(ntohl(ifs.int_addr)) ||
1101*0Sstevel@tonic-gate 		    (ntohl(ifs.int_addr) & IN_CLASSA_NET) == 0) {
1102*0Sstevel@tonic-gate 			if (IS_IFF_UP(ifs.int_if_flags)) {
1103*0Sstevel@tonic-gate 				if (!(prev_complaints & COMP_BADADDR))
1104*0Sstevel@tonic-gate 					writelog(LOG_NOTICE,
1105*0Sstevel@tonic-gate 					    "%s has a bad address %s",
1106*0Sstevel@tonic-gate 					    ifs.int_name,
1107*0Sstevel@tonic-gate 					    naddr_ntoa(ifs.int_addr));
1108*0Sstevel@tonic-gate 				complaints |= COMP_BADADDR;
1109*0Sstevel@tonic-gate 			}
1110*0Sstevel@tonic-gate 			continue;
1111*0Sstevel@tonic-gate 		}
1112*0Sstevel@tonic-gate 
1113*0Sstevel@tonic-gate 		/* Get the interface index. */
1114*0Sstevel@tonic-gate 		if (ioctl(sock, SIOCGLIFINDEX, lifrp) == -1) {
1115*0Sstevel@tonic-gate 			ifindex = 0;
1116*0Sstevel@tonic-gate 			ifs.int_if_flags &= ~IFF_UP;
1117*0Sstevel@tonic-gate 			if (!(prev_complaints & COMP_NO_INDEX))
1118*0Sstevel@tonic-gate 				writelog(LOG_NOTICE, "%s has no ifIndex: %s",
1119*0Sstevel@tonic-gate 				    ifs.int_name, rip_strerror(errno));
1120*0Sstevel@tonic-gate 			complaints |= COMP_NO_INDEX;
1121*0Sstevel@tonic-gate 		} else {
1122*0Sstevel@tonic-gate 			ifindex = lifrp->lifr_index;
1123*0Sstevel@tonic-gate 		}
1124*0Sstevel@tonic-gate 
1125*0Sstevel@tonic-gate 		/*
1126*0Sstevel@tonic-gate 		 * Get the destination address for point-to-point
1127*0Sstevel@tonic-gate 		 * interfaces.
1128*0Sstevel@tonic-gate 		 */
1129*0Sstevel@tonic-gate 		if (ifs.int_if_flags & IFF_POINTOPOINT) {
1130*0Sstevel@tonic-gate 			sinp = (struct sockaddr_in *)&lifrp->lifr_dstaddr;
1131*0Sstevel@tonic-gate 			if (ioctl(sock, SIOCGLIFDSTADDR, lifrp) == -1) {
1132*0Sstevel@tonic-gate 				if (IS_IFF_UP(ifs.int_if_flags)) {
1133*0Sstevel@tonic-gate 					if (!(prev_complaints & COMP_NODST))
1134*0Sstevel@tonic-gate 						writelog(LOG_NOTICE,
1135*0Sstevel@tonic-gate 						    "%s has no destination "
1136*0Sstevel@tonic-gate 						    "address : %s",
1137*0Sstevel@tonic-gate 						    ifs.int_name,
1138*0Sstevel@tonic-gate 						    rip_strerror(errno));
1139*0Sstevel@tonic-gate 					complaints |= COMP_NODST;
1140*0Sstevel@tonic-gate 				}
1141*0Sstevel@tonic-gate 				continue;
1142*0Sstevel@tonic-gate 			}
1143*0Sstevel@tonic-gate 			ifs.int_net = ntohl(sinp->sin_addr.s_addr);
1144*0Sstevel@tonic-gate 			if (IN_EXPERIMENTAL(ifs.int_net) ||
1145*0Sstevel@tonic-gate 			    (ifs.int_net != 0 &&
1146*0Sstevel@tonic-gate 			    (ifs.int_net & IN_CLASSA_NET) == 0)) {
1147*0Sstevel@tonic-gate 				if (IS_IFF_UP(ifs.int_if_flags)) {
1148*0Sstevel@tonic-gate 					if (!(prev_complaints & COMP_NODST))
1149*0Sstevel@tonic-gate 						writelog(LOG_NOTICE,
1150*0Sstevel@tonic-gate 						    "%s has a bad "
1151*0Sstevel@tonic-gate 						    "destination address %s",
1152*0Sstevel@tonic-gate 						    ifs.int_name,
1153*0Sstevel@tonic-gate 						    naddr_ntoa(ifs.int_net));
1154*0Sstevel@tonic-gate 					complaints |= COMP_NODST;
1155*0Sstevel@tonic-gate 				}
1156*0Sstevel@tonic-gate 				continue;
1157*0Sstevel@tonic-gate 			}
1158*0Sstevel@tonic-gate 			ifs.int_dstaddr = sinp->sin_addr.s_addr;
1159*0Sstevel@tonic-gate 		}
1160*0Sstevel@tonic-gate 
1161*0Sstevel@tonic-gate 		/* Get the subnet mask */
1162*0Sstevel@tonic-gate 		sinp = (struct sockaddr_in *)&lifrp->lifr_addr;
1163*0Sstevel@tonic-gate 		if (ioctl(sock, SIOCGLIFNETMASK, lifrp) == -1) {
1164*0Sstevel@tonic-gate 			if (IS_IFF_UP(ifs.int_if_flags)) {
1165*0Sstevel@tonic-gate 				if (!(prev_complaints & COMP_NOMASK))
1166*0Sstevel@tonic-gate 					writelog(LOG_NOTICE,
1167*0Sstevel@tonic-gate 					    "%s has no netmask: %s",
1168*0Sstevel@tonic-gate 					    ifs.int_name, rip_strerror(errno));
1169*0Sstevel@tonic-gate 				complaints |= COMP_NOMASK;
1170*0Sstevel@tonic-gate 			}
1171*0Sstevel@tonic-gate 			continue;
1172*0Sstevel@tonic-gate 		}
1173*0Sstevel@tonic-gate 		if (sinp->sin_addr.s_addr == INADDR_ANY) {
1174*0Sstevel@tonic-gate 			if (!(ifs.int_if_flags &
1175*0Sstevel@tonic-gate 			    (IFF_POINTOPOINT|IFF_LOOPBACK))) {
1176*0Sstevel@tonic-gate 				if (IS_IFF_UP(ifs.int_if_flags)) {
1177*0Sstevel@tonic-gate 					if (!(prev_complaints & COMP_NOMASK))
1178*0Sstevel@tonic-gate 						writelog(LOG_NOTICE,
1179*0Sstevel@tonic-gate 						    "%s has all-zero netmask",
1180*0Sstevel@tonic-gate 						    ifs.int_name);
1181*0Sstevel@tonic-gate 					complaints |= COMP_NOMASK;
1182*0Sstevel@tonic-gate 				}
1183*0Sstevel@tonic-gate 				continue;
1184*0Sstevel@tonic-gate 			}
1185*0Sstevel@tonic-gate 			ifs.int_mask = IP_HOST_MASK;
1186*0Sstevel@tonic-gate 		} else {
1187*0Sstevel@tonic-gate 			ifs.int_mask = ntohl(sinp->sin_addr.s_addr);
1188*0Sstevel@tonic-gate 		}
1189*0Sstevel@tonic-gate 
1190*0Sstevel@tonic-gate 		/*
1191*0Sstevel@tonic-gate 		 * Get the broadcast address on broadcast capable
1192*0Sstevel@tonic-gate 		 * interfaces.
1193*0Sstevel@tonic-gate 		 */
1194*0Sstevel@tonic-gate 		if (ifs.int_if_flags & IFF_BROADCAST) {
1195*0Sstevel@tonic-gate 			if (ioctl(sock, SIOCGLIFBRDADDR, lifrp) == -1) {
1196*0Sstevel@tonic-gate 				if (IS_IFF_UP(ifs.int_if_flags)) {
1197*0Sstevel@tonic-gate 					if (!(prev_complaints & COMP_NOBADDR))
1198*0Sstevel@tonic-gate 						writelog(LOG_NOTICE,
1199*0Sstevel@tonic-gate 						    "%s has no broadcast "
1200*0Sstevel@tonic-gate 						    "address: %s",
1201*0Sstevel@tonic-gate 						    ifs.int_name,
1202*0Sstevel@tonic-gate 						    rip_strerror(errno));
1203*0Sstevel@tonic-gate 					complaints |= COMP_NOBADDR;
1204*0Sstevel@tonic-gate 				}
1205*0Sstevel@tonic-gate 				continue;
1206*0Sstevel@tonic-gate 			}
1207*0Sstevel@tonic-gate 			haddr = ntohl(sinp->sin_addr.s_addr);
1208*0Sstevel@tonic-gate 			if (IN_EXPERIMENTAL(haddr) ||
1209*0Sstevel@tonic-gate 			    (haddr & IN_CLASSA_NET) == 0) {
1210*0Sstevel@tonic-gate 				if (IS_IFF_UP(ifs.int_if_flags)) {
1211*0Sstevel@tonic-gate 					if (!(prev_complaints & COMP_NOBADDR))
1212*0Sstevel@tonic-gate 						writelog(LOG_NOTICE,
1213*0Sstevel@tonic-gate 						    "%s has a bad broadcast "
1214*0Sstevel@tonic-gate 						    "address %s",
1215*0Sstevel@tonic-gate 						    ifs.int_name,
1216*0Sstevel@tonic-gate 						    naddr_ntoa(haddr));
1217*0Sstevel@tonic-gate 					complaints |= COMP_NOBADDR;
1218*0Sstevel@tonic-gate 				}
1219*0Sstevel@tonic-gate 				continue;
1220*0Sstevel@tonic-gate 			}
1221*0Sstevel@tonic-gate 		}
1222*0Sstevel@tonic-gate 		ifs.int_brdaddr = sinp->sin_addr.s_addr;
1223*0Sstevel@tonic-gate 
1224*0Sstevel@tonic-gate 		/* Get interface metric, if possible. */
1225*0Sstevel@tonic-gate 		if (ioctl(sock, SIOCGLIFMETRIC, lifrp) == -1) {
1226*0Sstevel@tonic-gate 			if (IS_IFF_UP(ifs.int_if_flags)) {
1227*0Sstevel@tonic-gate 				if (!(prev_complaints & COMP_BAD_METRIC))
1228*0Sstevel@tonic-gate 					writelog(LOG_NOTICE,
1229*0Sstevel@tonic-gate 					    "%s has no metric: %s",
1230*0Sstevel@tonic-gate 					    ifs.int_name, rip_strerror(errno));
1231*0Sstevel@tonic-gate 				complaints |= COMP_BAD_METRIC;
1232*0Sstevel@tonic-gate 			}
1233*0Sstevel@tonic-gate 		} else {
1234*0Sstevel@tonic-gate 			ifs.int_metric = lifrp->lifr_metric;
1235*0Sstevel@tonic-gate 			if (ifs.int_metric > HOPCNT_INFINITY) {
1236*0Sstevel@tonic-gate 				if (IS_IFF_UP(ifs.int_if_flags)) {
1237*0Sstevel@tonic-gate 					if (!(prev_complaints &
1238*0Sstevel@tonic-gate 					    COMP_BAD_METRIC))
1239*0Sstevel@tonic-gate 						writelog(LOG_NOTICE,
1240*0Sstevel@tonic-gate 						    "%s has a metric of %d, "
1241*0Sstevel@tonic-gate 						    "defaulting to %d",
1242*0Sstevel@tonic-gate 						    ifs.int_name,
1243*0Sstevel@tonic-gate 						    ifs.int_metric,
1244*0Sstevel@tonic-gate 						    HOPCNT_INFINITY);
1245*0Sstevel@tonic-gate 					complaints |= COMP_BAD_METRIC;
1246*0Sstevel@tonic-gate 				}
1247*0Sstevel@tonic-gate 				ifs.int_metric = HOPCNT_INFINITY;
1248*0Sstevel@tonic-gate 			}
1249*0Sstevel@tonic-gate 		}
1250*0Sstevel@tonic-gate 
1251*0Sstevel@tonic-gate 		ifs.int_state |= IS_CHECKED;
1252*0Sstevel@tonic-gate 		ifs.int_query_time = NEVER;
1253*0Sstevel@tonic-gate 
1254*0Sstevel@tonic-gate 		/*
1255*0Sstevel@tonic-gate 		 * If this is an alias, then mark it appropriately.
1256*0Sstevel@tonic-gate 		 * Do not output RIP or Router-Discovery packets via
1257*0Sstevel@tonic-gate 		 * aliases.
1258*0Sstevel@tonic-gate 		 */
1259*0Sstevel@tonic-gate 		if (strchr(ifs.int_name, ':') != NULL)
1260*0Sstevel@tonic-gate 			ifs.int_state |= IS_ALIAS;
1261*0Sstevel@tonic-gate 
1262*0Sstevel@tonic-gate 		if (ifs.int_if_flags & IFF_LOOPBACK) {
1263*0Sstevel@tonic-gate 			ifs.int_state |= IS_PASSIVE | IS_NO_RIP | IS_NO_RDISC;
1264*0Sstevel@tonic-gate 			ifs.int_dstaddr = ifs.int_addr;
1265*0Sstevel@tonic-gate 			ifs.int_mask = HOST_MASK;
1266*0Sstevel@tonic-gate 			ifs.int_ripv1_mask = HOST_MASK;
1267*0Sstevel@tonic-gate 			ifs.int_std_mask = std_mask(ifs.int_dstaddr);
1268*0Sstevel@tonic-gate 			ifs.int_net = ntohl(ifs.int_dstaddr);
1269*0Sstevel@tonic-gate 			if (!foundloopback) {
1270*0Sstevel@tonic-gate 				foundloopback = _B_TRUE;
1271*0Sstevel@tonic-gate 				loopaddr = ifs.int_addr;
1272*0Sstevel@tonic-gate 				loop_rts.rts_gate = loopaddr;
1273*0Sstevel@tonic-gate 				loop_rts.rts_router = loopaddr;
1274*0Sstevel@tonic-gate 			}
1275*0Sstevel@tonic-gate 
1276*0Sstevel@tonic-gate 		} else if (ifs.int_if_flags & IFF_POINTOPOINT) {
1277*0Sstevel@tonic-gate 			ifs.int_ripv1_mask = ifs.int_mask;
1278*0Sstevel@tonic-gate 			ifs.int_mask = HOST_MASK;
1279*0Sstevel@tonic-gate 			ifs.int_std_mask = std_mask(ifs.int_dstaddr);
1280*0Sstevel@tonic-gate 
1281*0Sstevel@tonic-gate 		} else {
1282*0Sstevel@tonic-gate 			ifs.int_dstaddr = ifs.int_addr;
1283*0Sstevel@tonic-gate 			ifs.int_ripv1_mask = ifs.int_mask;
1284*0Sstevel@tonic-gate 			ifs.int_std_mask = std_mask(ifs.int_addr);
1285*0Sstevel@tonic-gate 			ifs.int_net = ntohl(ifs.int_addr) & ifs.int_mask;
1286*0Sstevel@tonic-gate 			if (ifs.int_mask != ifs.int_std_mask)
1287*0Sstevel@tonic-gate 				ifs.int_state |= IS_SUBNET;
1288*0Sstevel@tonic-gate 		}
1289*0Sstevel@tonic-gate 		ifs.int_std_net = ifs.int_net & ifs.int_std_mask;
1290*0Sstevel@tonic-gate 		ifs.int_std_addr = htonl(ifs.int_std_net);
1291*0Sstevel@tonic-gate 
1292*0Sstevel@tonic-gate 		/*
1293*0Sstevel@tonic-gate 		 * If this interface duplicates another, mark it
1294*0Sstevel@tonic-gate 		 * appropriately so that we don't generate duplicate
1295*0Sstevel@tonic-gate 		 * packets.
1296*0Sstevel@tonic-gate 		 */
1297*0Sstevel@tonic-gate 		ifp = check_dup(ifs.int_name, ifs.int_addr, ifs.int_dstaddr,
1298*0Sstevel@tonic-gate 		    ifs.int_mask, ifs.int_if_flags, _B_FALSE);
1299*0Sstevel@tonic-gate 		if (ifp != NULL) {
1300*0Sstevel@tonic-gate 			trace_misc("%s (%s%s%s) is a duplicate of %s (%s%s%s)",
1301*0Sstevel@tonic-gate 			    ifs.int_name,
1302*0Sstevel@tonic-gate 			    addrname(ifs.int_addr, ifs.int_mask, 1),
1303*0Sstevel@tonic-gate 			    ((ifs.int_if_flags & IFF_POINTOPOINT) ?
1304*0Sstevel@tonic-gate 				"-->" : ""),
1305*0Sstevel@tonic-gate 			    ((ifs.int_if_flags & IFF_POINTOPOINT) ?
1306*0Sstevel@tonic-gate 				naddr_ntoa(ifs.int_dstaddr) : ""),
1307*0Sstevel@tonic-gate 			    ifp->int_name,
1308*0Sstevel@tonic-gate 			    addrname(ifp->int_addr, ifp->int_mask, 1),
1309*0Sstevel@tonic-gate 			    ((ifp->int_if_flags & IFF_POINTOPOINT) ?
1310*0Sstevel@tonic-gate 				"-->" : ""),
1311*0Sstevel@tonic-gate 			    ((ifp->int_if_flags & IFF_POINTOPOINT) ?
1312*0Sstevel@tonic-gate 				naddr_ntoa(ifp->int_dstaddr) : ""));
1313*0Sstevel@tonic-gate 			ifs.int_state |= IS_DUP;
1314*0Sstevel@tonic-gate 		} else {
1315*0Sstevel@tonic-gate 			ifs.int_state &= ~IS_DUP;
1316*0Sstevel@tonic-gate 		}
1317*0Sstevel@tonic-gate 
1318*0Sstevel@tonic-gate 		/*
1319*0Sstevel@tonic-gate 		 * See if this is a familiar interface.
1320*0Sstevel@tonic-gate 		 * If so, stop worrying about it if it is the same.
1321*0Sstevel@tonic-gate 		 * Start it over if it now is to somewhere else, as happens
1322*0Sstevel@tonic-gate 		 * frequently with PPP and SLIP, or if its forwarding
1323*0Sstevel@tonic-gate 		 * status has changed.
1324*0Sstevel@tonic-gate 		 */
1325*0Sstevel@tonic-gate 		ifp = ifwithname(ifs.int_name);
1326*0Sstevel@tonic-gate 		if (ifp != NULL) {
1327*0Sstevel@tonic-gate 			ifp->int_state |= IS_CHECKED;
1328*0Sstevel@tonic-gate 			ifp->int_state = (ifp->int_state & ~IS_DUP) |
1329*0Sstevel@tonic-gate 			    (ifs.int_state & IS_DUP);
1330*0Sstevel@tonic-gate 
1331*0Sstevel@tonic-gate 			if ((ifp->int_phys == NULL && ifindex != 0) ||
1332*0Sstevel@tonic-gate 			    (ifp->int_phys != NULL &&
1333*0Sstevel@tonic-gate 				ifp->int_phys->phyi_index != ifindex) ||
1334*0Sstevel@tonic-gate 			    0 != ((ifp->int_if_flags ^ ifs.int_if_flags)
1335*0Sstevel@tonic-gate 				& (IFF_BROADCAST | IFF_LOOPBACK |
1336*0Sstevel@tonic-gate 				IFF_POINTOPOINT | IFF_MULTICAST |
1337*0Sstevel@tonic-gate 				IFF_ROUTER | IFF_NORTEXCH | IFF_NOXMIT)) ||
1338*0Sstevel@tonic-gate 			    ifp->int_addr != ifs.int_addr ||
1339*0Sstevel@tonic-gate 			    ifp->int_brdaddr != ifs.int_brdaddr ||
1340*0Sstevel@tonic-gate 			    ifp->int_dstaddr != ifs.int_dstaddr ||
1341*0Sstevel@tonic-gate 			    ifp->int_mask != ifs.int_mask ||
1342*0Sstevel@tonic-gate 			    ifp->int_metric != ifs.int_metric) {
1343*0Sstevel@tonic-gate 				/*
1344*0Sstevel@tonic-gate 				 * Forget old information about
1345*0Sstevel@tonic-gate 				 * a changed interface.
1346*0Sstevel@tonic-gate 				 */
1347*0Sstevel@tonic-gate 				trace_act("interface %s has changed",
1348*0Sstevel@tonic-gate 				    ifp->int_name);
1349*0Sstevel@tonic-gate 				ifdel(ifp);
1350*0Sstevel@tonic-gate 				ifp = NULL;
1351*0Sstevel@tonic-gate 			}
1352*0Sstevel@tonic-gate 		}
1353*0Sstevel@tonic-gate 
1354*0Sstevel@tonic-gate 		if (ifp != NULL) {
1355*0Sstevel@tonic-gate 			/* note interfaces that have been turned off */
1356*0Sstevel@tonic-gate 			if (!IS_IFF_UP(ifs.int_if_flags)) {
1357*0Sstevel@tonic-gate 				if (IS_IFF_UP(ifp->int_if_flags)) {
1358*0Sstevel@tonic-gate 					writelog(LOG_WARNING,
1359*0Sstevel@tonic-gate 					    "interface %s to %s turned off",
1360*0Sstevel@tonic-gate 					    ifp->int_name,
1361*0Sstevel@tonic-gate 					    naddr_ntoa(ifp->int_dstaddr));
1362*0Sstevel@tonic-gate 					if_bad(ifp, _B_FALSE);
1363*0Sstevel@tonic-gate 					ifp->int_if_flags &= ~IFF_UP;
1364*0Sstevel@tonic-gate 				} else if (ifp->int_phys != NULL &&
1365*0Sstevel@tonic-gate 				    now.tv_sec > (ifp->int_phys->phyi_data.ts +
1366*0Sstevel@tonic-gate 				    CHECK_BAD_INTERVAL)) {
1367*0Sstevel@tonic-gate 					trace_act("interface %s has been off"
1368*0Sstevel@tonic-gate 					    " %ld seconds; forget it",
1369*0Sstevel@tonic-gate 					    ifp->int_name,
1370*0Sstevel@tonic-gate 					    now.tv_sec -
1371*0Sstevel@tonic-gate 					    ifp->int_phys->phyi_data.ts);
1372*0Sstevel@tonic-gate 					ifdel(ifp);
1373*0Sstevel@tonic-gate 				}
1374*0Sstevel@tonic-gate 				continue;
1375*0Sstevel@tonic-gate 			}
1376*0Sstevel@tonic-gate 			/* or that were off and are now ok */
1377*0Sstevel@tonic-gate 			if (!IS_IFF_UP(ifp->int_if_flags)) {
1378*0Sstevel@tonic-gate 				ifp->int_if_flags |= IFF_UP;
1379*0Sstevel@tonic-gate 				if_ok(ifp, "", _B_FALSE);
1380*0Sstevel@tonic-gate 			}
1381*0Sstevel@tonic-gate 
1382*0Sstevel@tonic-gate 			/*
1383*0Sstevel@tonic-gate 			 * If it has been long enough,
1384*0Sstevel@tonic-gate 			 * see if the interface is broken.
1385*0Sstevel@tonic-gate 			 */
1386*0Sstevel@tonic-gate 			if ((phyi = ifp->int_phys) == NULL ||
1387*0Sstevel@tonic-gate 			    now.tv_sec < phyi->phyi_data.ts +
1388*0Sstevel@tonic-gate 			    CHECK_BAD_INTERVAL)
1389*0Sstevel@tonic-gate 				continue;
1390*0Sstevel@tonic-gate 
1391*0Sstevel@tonic-gate 			(void) memset(&newstats, 0, sizeof (newstats));
1392*0Sstevel@tonic-gate 			if (get_if_kstats(ifp, &newstats) == -1) {
1393*0Sstevel@tonic-gate 				if (!(prev_complaints & COMP_NO_KSTATS))
1394*0Sstevel@tonic-gate 					writelog(LOG_WARNING,
1395*0Sstevel@tonic-gate 					    "unable to obtain kstats for %s",
1396*0Sstevel@tonic-gate 					    phyi->phyi_name);
1397*0Sstevel@tonic-gate 				complaints |= COMP_NO_KSTATS;
1398*0Sstevel@tonic-gate 			}
1399*0Sstevel@tonic-gate 
1400*0Sstevel@tonic-gate 			/*
1401*0Sstevel@tonic-gate 			 * If the interface just awoke, restart the counters.
1402*0Sstevel@tonic-gate 			 */
1403*0Sstevel@tonic-gate 			if (phyi->phyi_data.ts == 0) {
1404*0Sstevel@tonic-gate 				phyi->phyi_data = newstats;
1405*0Sstevel@tonic-gate 				continue;
1406*0Sstevel@tonic-gate 			}
1407*0Sstevel@tonic-gate 
1408*0Sstevel@tonic-gate 			in = newstats.ipackets - phyi->phyi_data.ipackets;
1409*0Sstevel@tonic-gate 			ierr = newstats.ierrors - phyi->phyi_data.ierrors;
1410*0Sstevel@tonic-gate 			out = newstats.opackets - phyi->phyi_data.opackets;
1411*0Sstevel@tonic-gate 			oerr = newstats.oerrors - phyi->phyi_data.oerrors;
1412*0Sstevel@tonic-gate 			phyi->phyi_data = newstats;
1413*0Sstevel@tonic-gate 
1414*0Sstevel@tonic-gate 			/*
1415*0Sstevel@tonic-gate 			 * Withhold judgment when the short error counters
1416*0Sstevel@tonic-gate 			 * wrap, the interface is reset, or if there are
1417*0Sstevel@tonic-gate 			 * no kstats.
1418*0Sstevel@tonic-gate 			 */
1419*0Sstevel@tonic-gate 			if (ierr < 0 || in < 0 || oerr < 0 || out < 0 ||
1420*0Sstevel@tonic-gate 			    newstats.ts == 0) {
1421*0Sstevel@tonic-gate 				LIM_SEC(ifscan_timer,
1422*0Sstevel@tonic-gate 				    now.tv_sec + CHECK_BAD_INTERVAL);
1423*0Sstevel@tonic-gate 				continue;
1424*0Sstevel@tonic-gate 			}
1425*0Sstevel@tonic-gate 
1426*0Sstevel@tonic-gate 			/* Withhold judgement when there is no traffic */
1427*0Sstevel@tonic-gate 			if (in == 0 && out == 0 && ierr == 0 && oerr == 0)
1428*0Sstevel@tonic-gate 				continue;
1429*0Sstevel@tonic-gate 
1430*0Sstevel@tonic-gate 			/*
1431*0Sstevel@tonic-gate 			 * It is bad if at least 25% of input or output on
1432*0Sstevel@tonic-gate 			 * an interface results in errors.  Require
1433*0Sstevel@tonic-gate 			 * presistent problems before marking it dead.
1434*0Sstevel@tonic-gate 			 */
1435*0Sstevel@tonic-gate 			if ((ierr > 0 && ierr >= in/4) ||
1436*0Sstevel@tonic-gate 			    (oerr > 0 && oerr >= out/4)) {
1437*0Sstevel@tonic-gate 				if (!(ifp->int_state & IS_SICK)) {
1438*0Sstevel@tonic-gate 					trace_act("interface %s to %s"
1439*0Sstevel@tonic-gate 					    " sick: in=%d ierr=%d"
1440*0Sstevel@tonic-gate 					    " out=%d oerr=%d",
1441*0Sstevel@tonic-gate 					    ifp->int_name,
1442*0Sstevel@tonic-gate 					    naddr_ntoa(ifp->int_dstaddr),
1443*0Sstevel@tonic-gate 					    in, ierr, out, oerr);
1444*0Sstevel@tonic-gate 					if_sick(ifp, _B_TRUE);
1445*0Sstevel@tonic-gate 					continue;
1446*0Sstevel@tonic-gate 				}
1447*0Sstevel@tonic-gate 				if (!(ifp->int_state & IS_BROKE)) {
1448*0Sstevel@tonic-gate 					writelog(LOG_WARNING,
1449*0Sstevel@tonic-gate 					    "interface %s to %s broken:"
1450*0Sstevel@tonic-gate 					    " in=%d ierr=%d out=%d oerr=%d",
1451*0Sstevel@tonic-gate 					    ifp->int_name,
1452*0Sstevel@tonic-gate 					    naddr_ntoa(ifp->int_dstaddr),
1453*0Sstevel@tonic-gate 					    in, ierr, out, oerr);
1454*0Sstevel@tonic-gate 					if_bad(ifp, _B_TRUE);
1455*0Sstevel@tonic-gate 				}
1456*0Sstevel@tonic-gate 				continue;
1457*0Sstevel@tonic-gate 			}
1458*0Sstevel@tonic-gate 
1459*0Sstevel@tonic-gate 			/* otherwise, it is active and healthy */
1460*0Sstevel@tonic-gate 			ifp->int_act_time = now.tv_sec;
1461*0Sstevel@tonic-gate 			if_ok(ifp, "", _B_TRUE);
1462*0Sstevel@tonic-gate 			continue;
1463*0Sstevel@tonic-gate 		}
1464*0Sstevel@tonic-gate 
1465*0Sstevel@tonic-gate 		/*
1466*0Sstevel@tonic-gate 		 * This is a new interface.
1467*0Sstevel@tonic-gate 		 * If it is dead, forget it.
1468*0Sstevel@tonic-gate 		 */
1469*0Sstevel@tonic-gate 		if (!IS_IFF_UP(ifs.int_if_flags))
1470*0Sstevel@tonic-gate 			continue;
1471*0Sstevel@tonic-gate 
1472*0Sstevel@tonic-gate 		if (0 == (ifs.int_if_flags & (IFF_POINTOPOINT |
1473*0Sstevel@tonic-gate 		    IFF_BROADCAST | IFF_LOOPBACK)) &&
1474*0Sstevel@tonic-gate 		    !(ifs.int_state & IS_PASSIVE)) {
1475*0Sstevel@tonic-gate 			if (!(prev_complaints & COMP_BAD_FLAGS))
1476*0Sstevel@tonic-gate 				trace_act("%s is neither broadcast, "
1477*0Sstevel@tonic-gate 				    "point-to-point, nor loopback",
1478*0Sstevel@tonic-gate 				    ifs.int_name);
1479*0Sstevel@tonic-gate 			complaints |= COMP_BAD_FLAGS;
1480*0Sstevel@tonic-gate 			if (!(ifs.int_if_flags & IFF_MULTICAST))
1481*0Sstevel@tonic-gate 				ifs.int_state |= IS_NO_RDISC;
1482*0Sstevel@tonic-gate 		}
1483*0Sstevel@tonic-gate 
1484*0Sstevel@tonic-gate 
1485*0Sstevel@tonic-gate 		/*
1486*0Sstevel@tonic-gate 		 * It is new and ok.   Add it to the list of interfaces
1487*0Sstevel@tonic-gate 		 */
1488*0Sstevel@tonic-gate 		ifp = rtmalloc(sizeof (*ifp), "ifscan ifp");
1489*0Sstevel@tonic-gate 		(void) memcpy(ifp, &ifs, sizeof (*ifp));
1490*0Sstevel@tonic-gate 		get_parms(ifp);
1491*0Sstevel@tonic-gate 		if_link(ifp, ifindex);
1492*0Sstevel@tonic-gate 		trace_if("Add", ifp);
1493*0Sstevel@tonic-gate 
1494*0Sstevel@tonic-gate 		if (ifp->int_phys != NULL &&
1495*0Sstevel@tonic-gate 		    get_if_kstats(ifp, &ifp->int_phys->phyi_data) == -1) {
1496*0Sstevel@tonic-gate 			if (!(prev_complaints & COMP_NO_KSTATS))
1497*0Sstevel@tonic-gate 				writelog(LOG_NOTICE,
1498*0Sstevel@tonic-gate 				    "unable to obtain kstats for %s",
1499*0Sstevel@tonic-gate 				    ifp->int_phys->phyi_name);
1500*0Sstevel@tonic-gate 			complaints |= COMP_NO_KSTATS;
1501*0Sstevel@tonic-gate 		}
1502*0Sstevel@tonic-gate 
1503*0Sstevel@tonic-gate 		/* Detect interfaces that have conflicting netmasks. */
1504*0Sstevel@tonic-gate 		if (!(ifp->int_if_flags & (IFF_POINTOPOINT|IFF_LOOPBACK))) {
1505*0Sstevel@tonic-gate 			for (ifp1 = ifnet; ifp1 != NULL;
1506*0Sstevel@tonic-gate 			    ifp1 = ifp1->int_next) {
1507*0Sstevel@tonic-gate 				if (ifp1->int_mask == ifp->int_mask)
1508*0Sstevel@tonic-gate 					continue;
1509*0Sstevel@tonic-gate 
1510*0Sstevel@tonic-gate 				/*
1511*0Sstevel@tonic-gate 				 * we don't care about point-to-point
1512*0Sstevel@tonic-gate 				 * or loopback aliases
1513*0Sstevel@tonic-gate 				 */
1514*0Sstevel@tonic-gate 				if (ifp1->int_if_flags &
1515*0Sstevel@tonic-gate 				    (IFF_POINTOPOINT|IFF_LOOPBACK)) {
1516*0Sstevel@tonic-gate 					continue;
1517*0Sstevel@tonic-gate 				}
1518*0Sstevel@tonic-gate 
1519*0Sstevel@tonic-gate 				/* ignore aliases on the same network */
1520*0Sstevel@tonic-gate 				if (ifp->int_phys == ifp1->int_phys)
1521*0Sstevel@tonic-gate 					continue;
1522*0Sstevel@tonic-gate 
1523*0Sstevel@tonic-gate 				if (on_net(ifp->int_addr,
1524*0Sstevel@tonic-gate 				    ifp1->int_net, ifp1->int_mask) ||
1525*0Sstevel@tonic-gate 				    on_net(ifp1->int_addr,
1526*0Sstevel@tonic-gate 					ifp->int_net, ifp->int_mask)) {
1527*0Sstevel@tonic-gate 					writelog(LOG_INFO,
1528*0Sstevel@tonic-gate 					    "possible netmask problem"
1529*0Sstevel@tonic-gate 					    " between %s:%s and %s:%s",
1530*0Sstevel@tonic-gate 					    ifp->int_name,
1531*0Sstevel@tonic-gate 					    addrname(htonl(ifp->int_net),
1532*0Sstevel@tonic-gate 						ifp->int_mask, 1),
1533*0Sstevel@tonic-gate 					    ifp1->int_name,
1534*0Sstevel@tonic-gate 					    addrname(htonl(ifp1->int_net),
1535*0Sstevel@tonic-gate 						ifp1->int_mask, 1));
1536*0Sstevel@tonic-gate 					complaints |= COMP_NETMASK;
1537*0Sstevel@tonic-gate 				}
1538*0Sstevel@tonic-gate 			}
1539*0Sstevel@tonic-gate 		}
1540*0Sstevel@tonic-gate 
1541*0Sstevel@tonic-gate 		if (!(ifp->int_state & IS_DUP) &&
1542*0Sstevel@tonic-gate 		    !IS_IFF_QUIET(ifp->int_if_flags)) {
1543*0Sstevel@tonic-gate 			/* Count the # of directly connected networks. */
1544*0Sstevel@tonic-gate 			tot_interfaces++;
1545*0Sstevel@tonic-gate 			if (!IS_RIP_OFF(ifp->int_state))
1546*0Sstevel@tonic-gate 				rip_interfaces++;
1547*0Sstevel@tonic-gate 			if (!IS_RIP_OUT_OFF(ifp->int_state))
1548*0Sstevel@tonic-gate 				ripout_interfaces++;
1549*0Sstevel@tonic-gate 			if (IS_IFF_ROUTING(ifp->int_if_flags))
1550*0Sstevel@tonic-gate 				fwd_interfaces++;
1551*0Sstevel@tonic-gate 
1552*0Sstevel@tonic-gate 			if_ok_rdisc(ifp);
1553*0Sstevel@tonic-gate 			rip_on(ifp);
1554*0Sstevel@tonic-gate 		}
1555*0Sstevel@tonic-gate 	}
1556*0Sstevel@tonic-gate 
1557*0Sstevel@tonic-gate 	(void) close(sock);
1558*0Sstevel@tonic-gate 
1559*0Sstevel@tonic-gate 	/*
1560*0Sstevel@tonic-gate 	 * If we are multi-homed and have at least two interfaces that
1561*0Sstevel@tonic-gate 	 * are able to forward, then output RIP by default.
1562*0Sstevel@tonic-gate 	 */
1563*0Sstevel@tonic-gate 	if (!supplier_set)
1564*0Sstevel@tonic-gate 		set_supplier();
1565*0Sstevel@tonic-gate 
1566*0Sstevel@tonic-gate 	/*
1567*0Sstevel@tonic-gate 	 * If we are multi-homed, optionally advertise a route to
1568*0Sstevel@tonic-gate 	 * our main address.
1569*0Sstevel@tonic-gate 	 */
1570*0Sstevel@tonic-gate 	if (advertise_mhome || (tot_interfaces > 1 && mhome)) {
1571*0Sstevel@tonic-gate 		/* lookup myaddr if we haven't done so already */
1572*0Sstevel@tonic-gate 		if (myaddr == 0) {
1573*0Sstevel@tonic-gate 			char myname[MAXHOSTNAMELEN+1];
1574*0Sstevel@tonic-gate 
1575*0Sstevel@tonic-gate 			/*
1576*0Sstevel@tonic-gate 			 * If we are unable to resolve our hostname, don't
1577*0Sstevel@tonic-gate 			 * bother trying again.
1578*0Sstevel@tonic-gate 			 */
1579*0Sstevel@tonic-gate 			if (gethostname(myname, MAXHOSTNAMELEN) == -1) {
1580*0Sstevel@tonic-gate 				msglog("gethostname: %s", rip_strerror(errno));
1581*0Sstevel@tonic-gate 				advertise_mhome = _B_FALSE;
1582*0Sstevel@tonic-gate 				mhome = _B_FALSE;
1583*0Sstevel@tonic-gate 			} else if (gethost(myname, &myaddr) == 0) {
1584*0Sstevel@tonic-gate 				writelog(LOG_WARNING,
1585*0Sstevel@tonic-gate 				    "unable to resolve local hostname %s",
1586*0Sstevel@tonic-gate 				    myname);
1587*0Sstevel@tonic-gate 				advertise_mhome = _B_FALSE;
1588*0Sstevel@tonic-gate 				mhome = _B_FALSE;
1589*0Sstevel@tonic-gate 			}
1590*0Sstevel@tonic-gate 		}
1591*0Sstevel@tonic-gate 		if (myaddr != 0 &&
1592*0Sstevel@tonic-gate 		    (ifp = ifwithaddr(myaddr, _B_FALSE, _B_FALSE)) != NULL &&
1593*0Sstevel@tonic-gate 		    foundloopback) {
1594*0Sstevel@tonic-gate 			advertise_mhome = _B_TRUE;
1595*0Sstevel@tonic-gate 			rt = rtget(myaddr, HOST_MASK);
1596*0Sstevel@tonic-gate 			if (rt != NULL) {
1597*0Sstevel@tonic-gate 				if (rt->rt_ifp != ifp ||
1598*0Sstevel@tonic-gate 				    rt->rt_router != loopaddr) {
1599*0Sstevel@tonic-gate 					rtdelete(rt);
1600*0Sstevel@tonic-gate 					rt = NULL;
1601*0Sstevel@tonic-gate 				} else {
1602*0Sstevel@tonic-gate 					loop_rts.rts_ifp = ifp;
1603*0Sstevel@tonic-gate 					loop_rts.rts_metric = 0;
1604*0Sstevel@tonic-gate 					loop_rts.rts_time = rt->rt_time;
1605*0Sstevel@tonic-gate 					loop_rts.rts_origin = RO_LOOPBCK;
1606*0Sstevel@tonic-gate 					rtchange(rt, rt->rt_state | RS_MHOME,
1607*0Sstevel@tonic-gate 					    &loop_rts, NULL);
1608*0Sstevel@tonic-gate 				}
1609*0Sstevel@tonic-gate 			}
1610*0Sstevel@tonic-gate 			if (rt == NULL) {
1611*0Sstevel@tonic-gate 				loop_rts.rts_ifp = ifp;
1612*0Sstevel@tonic-gate 				loop_rts.rts_metric = 0;
1613*0Sstevel@tonic-gate 				loop_rts.rts_origin = RO_LOOPBCK;
1614*0Sstevel@tonic-gate 				rtadd(myaddr, HOST_MASK, RS_MHOME, &loop_rts);
1615*0Sstevel@tonic-gate 			}
1616*0Sstevel@tonic-gate 		}
1617*0Sstevel@tonic-gate 	}
1618*0Sstevel@tonic-gate 
1619*0Sstevel@tonic-gate 	for (ifp = ifnet; ifp != NULL; ifp = ifp1) {
1620*0Sstevel@tonic-gate 		ifp1 = ifp->int_next;	/* because we may delete it */
1621*0Sstevel@tonic-gate 
1622*0Sstevel@tonic-gate 		/* Forget any interfaces that have disappeared. */
1623*0Sstevel@tonic-gate 		if (!(ifp->int_state & (IS_CHECKED | IS_REMOTE))) {
1624*0Sstevel@tonic-gate 			trace_act("interface %s has disappeared",
1625*0Sstevel@tonic-gate 			    ifp->int_name);
1626*0Sstevel@tonic-gate 			ifdel(ifp);
1627*0Sstevel@tonic-gate 			continue;
1628*0Sstevel@tonic-gate 		}
1629*0Sstevel@tonic-gate 
1630*0Sstevel@tonic-gate 		if ((ifp->int_state & IS_BROKE) &&
1631*0Sstevel@tonic-gate 		    !(ifp->int_state & IS_PASSIVE))
1632*0Sstevel@tonic-gate 			LIM_SEC(ifscan_timer, now.tv_sec+CHECK_BAD_INTERVAL);
1633*0Sstevel@tonic-gate 
1634*0Sstevel@tonic-gate 		/*
1635*0Sstevel@tonic-gate 		 * If we ever have a RIPv1 interface, assume we always will.
1636*0Sstevel@tonic-gate 		 * It might come back if it ever goes away.
1637*0Sstevel@tonic-gate 		 */
1638*0Sstevel@tonic-gate 		if (!(ifp->int_state & (IS_NO_RIPV1_OUT | IS_DUP)) &&
1639*0Sstevel@tonic-gate 		    should_supply(ifp))
1640*0Sstevel@tonic-gate 			have_ripv1_out = _B_TRUE;
1641*0Sstevel@tonic-gate 		if (!(ifp->int_state & IS_NO_RIPV1_IN))
1642*0Sstevel@tonic-gate 			have_ripv1_in = _B_TRUE;
1643*0Sstevel@tonic-gate 	}
1644*0Sstevel@tonic-gate 
1645*0Sstevel@tonic-gate 	for (ifp = ifnet; ifp != NULL; ifp = ifp->int_next) {
1646*0Sstevel@tonic-gate 		/*
1647*0Sstevel@tonic-gate 		 * Ensure there is always a network route for interfaces,
1648*0Sstevel@tonic-gate 		 * after any dead interfaces have been deleted, which
1649*0Sstevel@tonic-gate 		 * might affect routes for point-to-point links.
1650*0Sstevel@tonic-gate 		 */
1651*0Sstevel@tonic-gate 		if (addrouteforif(ifp) == 0)
1652*0Sstevel@tonic-gate 			continue;
1653*0Sstevel@tonic-gate 
1654*0Sstevel@tonic-gate 		/*
1655*0Sstevel@tonic-gate 		 * Add routes to the local end of point-to-point interfaces
1656*0Sstevel@tonic-gate 		 * using loopback.
1657*0Sstevel@tonic-gate 		 */
1658*0Sstevel@tonic-gate 		if ((ifp->int_if_flags & IFF_POINTOPOINT) &&
1659*0Sstevel@tonic-gate 		    !(ifp->int_state & IS_REMOTE) && foundloopback) {
1660*0Sstevel@tonic-gate 			/*
1661*0Sstevel@tonic-gate 			 * Delete any routes to the network address through
1662*0Sstevel@tonic-gate 			 * foreign routers. Remove even static routes.
1663*0Sstevel@tonic-gate 			 */
1664*0Sstevel@tonic-gate 			del_static(ifp->int_addr, HOST_MASK, 0, ifp, 0);
1665*0Sstevel@tonic-gate 			rt = rtget(ifp->int_addr, HOST_MASK);
1666*0Sstevel@tonic-gate 			if (rt != NULL && rt->rt_router != loopaddr) {
1667*0Sstevel@tonic-gate 				rtdelete(rt);
1668*0Sstevel@tonic-gate 				rt = NULL;
1669*0Sstevel@tonic-gate 			}
1670*0Sstevel@tonic-gate 			if (rt != NULL) {
1671*0Sstevel@tonic-gate 				if (!(rt->rt_state & RS_LOCAL) ||
1672*0Sstevel@tonic-gate 				    rt->rt_metric > ifp->int_metric) {
1673*0Sstevel@tonic-gate 					ifp1 = ifp;
1674*0Sstevel@tonic-gate 				} else {
1675*0Sstevel@tonic-gate 					ifp1 = rt->rt_ifp;
1676*0Sstevel@tonic-gate 				}
1677*0Sstevel@tonic-gate 				loop_rts.rts_ifp = ifp1;
1678*0Sstevel@tonic-gate 				loop_rts.rts_metric = 0;
1679*0Sstevel@tonic-gate 				loop_rts.rts_time = rt->rt_time;
1680*0Sstevel@tonic-gate 				loop_rts.rts_origin = RO_LOOPBCK;
1681*0Sstevel@tonic-gate 				rtchange(rt, ((rt->rt_state & ~RS_NET_SYN) |
1682*0Sstevel@tonic-gate 				    (RS_IF|RS_LOCAL)), &loop_rts, 0);
1683*0Sstevel@tonic-gate 			} else {
1684*0Sstevel@tonic-gate 				loop_rts.rts_ifp = ifp;
1685*0Sstevel@tonic-gate 				loop_rts.rts_metric = 0;
1686*0Sstevel@tonic-gate 				loop_rts.rts_origin = RO_LOOPBCK;
1687*0Sstevel@tonic-gate 				rtadd(ifp->int_addr, HOST_MASK,
1688*0Sstevel@tonic-gate 				    (RS_IF | RS_LOCAL), &loop_rts);
1689*0Sstevel@tonic-gate 			}
1690*0Sstevel@tonic-gate 		}
1691*0Sstevel@tonic-gate 	}
1692*0Sstevel@tonic-gate 
1693*0Sstevel@tonic-gate 	/* add the authority routes */
1694*0Sstevel@tonic-gate 	for (intnetp = intnets; intnetp != NULL;
1695*0Sstevel@tonic-gate 	    intnetp = intnetp->intnet_next) {
1696*0Sstevel@tonic-gate 		rt = rtget(intnetp->intnet_addr, intnetp->intnet_mask);
1697*0Sstevel@tonic-gate 		if (rt != NULL &&
1698*0Sstevel@tonic-gate 		    !(rt->rt_state & RS_NO_NET_SYN) &&
1699*0Sstevel@tonic-gate 		    !(rt->rt_state & RS_NET_INT)) {
1700*0Sstevel@tonic-gate 			rtdelete(rt);
1701*0Sstevel@tonic-gate 			rt = NULL;
1702*0Sstevel@tonic-gate 		}
1703*0Sstevel@tonic-gate 		if (rt == NULL) {
1704*0Sstevel@tonic-gate 			loop_rts.rts_ifp = NULL;
1705*0Sstevel@tonic-gate 			loop_rts.rts_metric = intnetp->intnet_metric-1;
1706*0Sstevel@tonic-gate 			loop_rts.rts_origin = RO_LOOPBCK;
1707*0Sstevel@tonic-gate 			rtadd(intnetp->intnet_addr, intnetp->intnet_mask,
1708*0Sstevel@tonic-gate 			    RS_NET_SYN | RS_NET_INT, &loop_rts);
1709*0Sstevel@tonic-gate 		}
1710*0Sstevel@tonic-gate 	}
1711*0Sstevel@tonic-gate 
1712*0Sstevel@tonic-gate 	prev_complaints = complaints;
1713*0Sstevel@tonic-gate }
1714*0Sstevel@tonic-gate 
1715*0Sstevel@tonic-gate 
1716*0Sstevel@tonic-gate static void
1717*0Sstevel@tonic-gate check_net_syn(struct interface *ifp)
1718*0Sstevel@tonic-gate {
1719*0Sstevel@tonic-gate 	struct rt_entry *rt;
1720*0Sstevel@tonic-gate 	struct rt_spare new;
1721*0Sstevel@tonic-gate 
1722*0Sstevel@tonic-gate 	/*
1723*0Sstevel@tonic-gate 	 * Turn on the need to automatically synthesize a network route
1724*0Sstevel@tonic-gate 	 * for this interface only if we are running RIPv1 on some other
1725*0Sstevel@tonic-gate 	 * interface that is on a different class-A,B,or C network.
1726*0Sstevel@tonic-gate 	 */
1727*0Sstevel@tonic-gate 	if (have_ripv1_out || have_ripv1_in) {
1728*0Sstevel@tonic-gate 		ifp->int_state |= IS_NEED_NET_SYN;
1729*0Sstevel@tonic-gate 		rt = rtget(ifp->int_std_addr, ifp->int_std_mask);
1730*0Sstevel@tonic-gate 		if (rt != NULL &&
1731*0Sstevel@tonic-gate 		    0 == (rt->rt_state & RS_NO_NET_SYN) &&
1732*0Sstevel@tonic-gate 		    (!(rt->rt_state & RS_NET_SYN) ||
1733*0Sstevel@tonic-gate 			rt->rt_metric > ifp->int_metric)) {
1734*0Sstevel@tonic-gate 			rtdelete(rt);
1735*0Sstevel@tonic-gate 			rt = NULL;
1736*0Sstevel@tonic-gate 		}
1737*0Sstevel@tonic-gate 		if (rt == NULL) {
1738*0Sstevel@tonic-gate 			(void) memset(&new, 0, sizeof (new));
1739*0Sstevel@tonic-gate 			new.rts_ifp = ifp;
1740*0Sstevel@tonic-gate 			new.rts_gate = ifp->int_addr;
1741*0Sstevel@tonic-gate 			new.rts_router = ifp->int_addr;
1742*0Sstevel@tonic-gate 			new.rts_metric = ifp->int_metric;
1743*0Sstevel@tonic-gate 			new.rts_origin = RO_NET_SYN;
1744*0Sstevel@tonic-gate 			rtadd(ifp->int_std_addr, ifp->int_std_mask,
1745*0Sstevel@tonic-gate 			    RS_NET_SYN, &new);
1746*0Sstevel@tonic-gate 		}
1747*0Sstevel@tonic-gate 
1748*0Sstevel@tonic-gate 	} else {
1749*0Sstevel@tonic-gate 		ifp->int_state &= ~IS_NEED_NET_SYN;
1750*0Sstevel@tonic-gate 
1751*0Sstevel@tonic-gate 		rt = rtget(ifp->int_std_addr, ifp->int_std_mask);
1752*0Sstevel@tonic-gate 		if (rt != NULL &&
1753*0Sstevel@tonic-gate 		    (rt->rt_state & RS_NET_SYN) &&
1754*0Sstevel@tonic-gate 		    rt->rt_ifp == ifp)
1755*0Sstevel@tonic-gate 			rtbad_sub(rt, NULL);
1756*0Sstevel@tonic-gate 	}
1757*0Sstevel@tonic-gate }
1758*0Sstevel@tonic-gate 
1759*0Sstevel@tonic-gate 
1760*0Sstevel@tonic-gate /*
1761*0Sstevel@tonic-gate  * Add route for interface if not currently installed.
1762*0Sstevel@tonic-gate  * Create route to other end if a point-to-point link,
1763*0Sstevel@tonic-gate  * otherwise a route to this (sub)network.
1764*0Sstevel@tonic-gate  */
1765*0Sstevel@tonic-gate static boolean_t			/* _B_FALSE=bad interface */
1766*0Sstevel@tonic-gate addrouteforif(struct interface *ifp)
1767*0Sstevel@tonic-gate {
1768*0Sstevel@tonic-gate 	struct rt_entry *rt;
1769*0Sstevel@tonic-gate 	struct rt_spare new;
1770*0Sstevel@tonic-gate 	in_addr_t dst;
1771*0Sstevel@tonic-gate 	uint16_t rt_newstate = RS_IF;
1772*0Sstevel@tonic-gate 
1773*0Sstevel@tonic-gate 
1774*0Sstevel@tonic-gate 	/* skip sick interfaces */
1775*0Sstevel@tonic-gate 	if (ifp->int_state & IS_BROKE)
1776*0Sstevel@tonic-gate 		return (_B_FALSE);
1777*0Sstevel@tonic-gate 
1778*0Sstevel@tonic-gate 	/*
1779*0Sstevel@tonic-gate 	 * don't install routes for duplicate interfaces, or
1780*0Sstevel@tonic-gate 	 * unnumbered point-to-point interfaces.
1781*0Sstevel@tonic-gate 	 */
1782*0Sstevel@tonic-gate 	if ((ifp->int_state & IS_DUP) ||
1783*0Sstevel@tonic-gate 	    ((ifp->int_if_flags & IFF_POINTOPOINT) && ifp->int_dstaddr == 0))
1784*0Sstevel@tonic-gate 		return (_B_TRUE);
1785*0Sstevel@tonic-gate 
1786*0Sstevel@tonic-gate 	/*
1787*0Sstevel@tonic-gate 	 * If the interface on a subnet, then install a RIPv1 route to
1788*0Sstevel@tonic-gate 	 * the network as well (unless it is sick).
1789*0Sstevel@tonic-gate 	 */
1790*0Sstevel@tonic-gate 	if (ifp->int_state & IS_SUBNET)
1791*0Sstevel@tonic-gate 		check_net_syn(ifp);
1792*0Sstevel@tonic-gate 
1793*0Sstevel@tonic-gate 	dst = (0 != (ifp->int_if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) ?
1794*0Sstevel@tonic-gate 	    ifp->int_dstaddr : htonl(ifp->int_net));
1795*0Sstevel@tonic-gate 
1796*0Sstevel@tonic-gate 	(void) memset(&new, 0, sizeof (new));
1797*0Sstevel@tonic-gate 	new.rts_ifp = ifp;
1798*0Sstevel@tonic-gate 	new.rts_router = ifp->int_addr;
1799*0Sstevel@tonic-gate 	new.rts_gate = ifp->int_addr;
1800*0Sstevel@tonic-gate 	new.rts_metric = ifp->int_metric;
1801*0Sstevel@tonic-gate 	new.rts_time = now.tv_sec;
1802*0Sstevel@tonic-gate 	if (ifp->int_if_flags & IFF_POINTOPOINT)
1803*0Sstevel@tonic-gate 		new.rts_origin = RO_PTOPT;
1804*0Sstevel@tonic-gate 	else if (ifp->int_if_flags & IFF_LOOPBACK)
1805*0Sstevel@tonic-gate 		new.rts_origin = RO_LOOPBCK;
1806*0Sstevel@tonic-gate 	else
1807*0Sstevel@tonic-gate 		new.rts_origin = RO_IF;
1808*0Sstevel@tonic-gate 
1809*0Sstevel@tonic-gate 	/*
1810*0Sstevel@tonic-gate 	 * If we are going to send packets to the gateway,
1811*0Sstevel@tonic-gate 	 * it must be reachable using our physical interfaces
1812*0Sstevel@tonic-gate 	 */
1813*0Sstevel@tonic-gate 	if ((ifp->int_state & IS_REMOTE) &&
1814*0Sstevel@tonic-gate 	    !(ifp->int_state & IS_EXTERNAL) &&
1815*0Sstevel@tonic-gate 	    !check_remote(ifp))
1816*0Sstevel@tonic-gate 		return (_B_FALSE);
1817*0Sstevel@tonic-gate 
1818*0Sstevel@tonic-gate 	/*
1819*0Sstevel@tonic-gate 	 * We are finished if the correct main interface route exists.
1820*0Sstevel@tonic-gate 	 * The right route must be for the right interface, not synthesized
1821*0Sstevel@tonic-gate 	 * from a subnet, be a "gateway" or not as appropriate, and so forth.
1822*0Sstevel@tonic-gate 	 */
1823*0Sstevel@tonic-gate 	del_static(dst, ifp->int_mask, 0, ifp, 0);
1824*0Sstevel@tonic-gate 	rt = rtget(dst, ifp->int_mask);
1825*0Sstevel@tonic-gate 	if (!IS_IFF_ROUTING(ifp->int_if_flags))
1826*0Sstevel@tonic-gate 		rt_newstate |= RS_NOPROPAGATE;
1827*0Sstevel@tonic-gate 	if (rt != NULL) {
1828*0Sstevel@tonic-gate 		if ((rt->rt_ifp != ifp || rt->rt_router != ifp->int_addr) &&
1829*0Sstevel@tonic-gate 		    (rt->rt_ifp == NULL ||
1830*0Sstevel@tonic-gate 		    (rt->rt_ifp->int_state & IS_BROKE))) {
1831*0Sstevel@tonic-gate 			rtdelete(rt);
1832*0Sstevel@tonic-gate 			rt = NULL;
1833*0Sstevel@tonic-gate 		} else {
1834*0Sstevel@tonic-gate 			rtchange(rt, ((rt->rt_state | rt_newstate) &
1835*0Sstevel@tonic-gate 			    ~(RS_NET_SYN | RS_LOCAL)), &new, 0);
1836*0Sstevel@tonic-gate 		}
1837*0Sstevel@tonic-gate 	}
1838*0Sstevel@tonic-gate 	if (rt == NULL) {
1839*0Sstevel@tonic-gate 		if (ifp->int_transitions++ > 0)
1840*0Sstevel@tonic-gate 			trace_act("re-installing interface %s;"
1841*0Sstevel@tonic-gate 			    " went up %d times",
1842*0Sstevel@tonic-gate 			    ifp->int_name, ifp->int_transitions);
1843*0Sstevel@tonic-gate 
1844*0Sstevel@tonic-gate 		rtadd(dst, ifp->int_mask, rt_newstate, &new);
1845*0Sstevel@tonic-gate 	}
1846*0Sstevel@tonic-gate 
1847*0Sstevel@tonic-gate 	return (_B_TRUE);
1848*0Sstevel@tonic-gate }
1849*0Sstevel@tonic-gate 
1850*0Sstevel@tonic-gate /*
1851*0Sstevel@tonic-gate  * Obtains the named kstat, and places its value in *value.  It
1852*0Sstevel@tonic-gate  * returns 0 for success, -1 for failure.
1853*0Sstevel@tonic-gate  */
1854*0Sstevel@tonic-gate static int
1855*0Sstevel@tonic-gate kstat_named_value(kstat_t *ksp, char *name, uint32_t *value)
1856*0Sstevel@tonic-gate {
1857*0Sstevel@tonic-gate 	kstat_named_t *knp;
1858*0Sstevel@tonic-gate 
1859*0Sstevel@tonic-gate 	if (ksp == NULL)
1860*0Sstevel@tonic-gate 		return (-1);
1861*0Sstevel@tonic-gate 
1862*0Sstevel@tonic-gate 	if ((knp = kstat_data_lookup(ksp, name)) == NULL) {
1863*0Sstevel@tonic-gate 		return (-1);
1864*0Sstevel@tonic-gate 	} else if (knp->data_type != KSTAT_DATA_UINT32) {
1865*0Sstevel@tonic-gate 		return (-1);
1866*0Sstevel@tonic-gate 	} else {
1867*0Sstevel@tonic-gate 		*value = knp->value.ui32;
1868*0Sstevel@tonic-gate 		return (0);
1869*0Sstevel@tonic-gate 	}
1870*0Sstevel@tonic-gate }
1871*0Sstevel@tonic-gate 
1872*0Sstevel@tonic-gate static int
1873*0Sstevel@tonic-gate get_if_kstats(struct interface *ifp, struct phyi_data *newdata)
1874*0Sstevel@tonic-gate {
1875*0Sstevel@tonic-gate 	struct physical_interface *phyi = ifp->int_phys;
1876*0Sstevel@tonic-gate 	kstat_ctl_t *kc;
1877*0Sstevel@tonic-gate 	kstat_t *ksp;
1878*0Sstevel@tonic-gate 
1879*0Sstevel@tonic-gate 	/* We did this recently; don't do it again. */
1880*0Sstevel@tonic-gate 	if (phyi->phyi_data.ts == now.tv_sec) {
1881*0Sstevel@tonic-gate 		if (newdata != &phyi->phyi_data)
1882*0Sstevel@tonic-gate 			*newdata = phyi->phyi_data;
1883*0Sstevel@tonic-gate 		return (0);
1884*0Sstevel@tonic-gate 	}
1885*0Sstevel@tonic-gate 
1886*0Sstevel@tonic-gate 	if ((kc = kstat_open()) == NULL)
1887*0Sstevel@tonic-gate 		return (-1);
1888*0Sstevel@tonic-gate 
1889*0Sstevel@tonic-gate 	if ((ksp = kstat_lookup(kc, NULL, -1, phyi->phyi_name)) == NULL) {
1890*0Sstevel@tonic-gate 		(void) kstat_close(kc);
1891*0Sstevel@tonic-gate 		return (-1);
1892*0Sstevel@tonic-gate 	}
1893*0Sstevel@tonic-gate 
1894*0Sstevel@tonic-gate 	if (kstat_read(kc, ksp, NULL) == -1) {
1895*0Sstevel@tonic-gate 		(void) kstat_close(kc);
1896*0Sstevel@tonic-gate 		return (-1);
1897*0Sstevel@tonic-gate 	}
1898*0Sstevel@tonic-gate 
1899*0Sstevel@tonic-gate 	if ((kstat_named_value(ksp, "ipackets", &newdata->ipackets) == -1) ||
1900*0Sstevel@tonic-gate 	    (kstat_named_value(ksp, "opackets",	&newdata->opackets) == -1)) {
1901*0Sstevel@tonic-gate 		newdata->ts = 0;
1902*0Sstevel@tonic-gate 		(void) kstat_close(kc);
1903*0Sstevel@tonic-gate 		return (-1);
1904*0Sstevel@tonic-gate 	}
1905*0Sstevel@tonic-gate 
1906*0Sstevel@tonic-gate 	/* The loopback interface does not keep track of errors */
1907*0Sstevel@tonic-gate 	if (!(ifp->int_if_flags & IFF_LOOPBACK)) {
1908*0Sstevel@tonic-gate 		if ((kstat_named_value(ksp, "ierrors",
1909*0Sstevel@tonic-gate 		    &newdata->ierrors) == -1) ||
1910*0Sstevel@tonic-gate 		    (kstat_named_value(ksp, "oerrors",
1911*0Sstevel@tonic-gate 		    &newdata->oerrors) == -1)) {
1912*0Sstevel@tonic-gate 			newdata->ts = 0;
1913*0Sstevel@tonic-gate 			(void) kstat_close(kc);
1914*0Sstevel@tonic-gate 			return (-1);
1915*0Sstevel@tonic-gate 		}
1916*0Sstevel@tonic-gate 	}
1917*0Sstevel@tonic-gate 
1918*0Sstevel@tonic-gate 	newdata->ts = now.tv_sec;
1919*0Sstevel@tonic-gate 	(void) kstat_close(kc);
1920*0Sstevel@tonic-gate 	return (0);
1921*0Sstevel@tonic-gate }
1922*0Sstevel@tonic-gate 
1923*0Sstevel@tonic-gate /*
1924*0Sstevel@tonic-gate  * Returns true if we should supply routes to other systems.  If the
1925*0Sstevel@tonic-gate  * user has forced us to be a supplier (by the command line) or if we
1926*0Sstevel@tonic-gate  * have more than one forwarding interface and this is one of the
1927*0Sstevel@tonic-gate  * forwarding interfaces, then behave as a RIP supplier (supply rdisc
1928*0Sstevel@tonic-gate  * advertisements and RIP responses).
1929*0Sstevel@tonic-gate  */
1930*0Sstevel@tonic-gate boolean_t
1931*0Sstevel@tonic-gate should_supply(struct interface *ifp)
1932*0Sstevel@tonic-gate {
1933*0Sstevel@tonic-gate 	if (ifp != NULL && !IS_IFF_ROUTING(ifp->int_if_flags))
1934*0Sstevel@tonic-gate 		return (_B_FALSE);
1935*0Sstevel@tonic-gate 	return ((supplier_set && supplier) ||
1936*0Sstevel@tonic-gate 	    (!supplier_set && fwd_interfaces > 1));
1937*0Sstevel@tonic-gate }
1938