xref: /titanic_41/usr/src/cmd/cmd-inet/usr.sbin/in.routed/if.c (revision 982ec2c2dc1163bc65216b4f07a4aa7c13c6aaf2)
17c478bd9Sstevel@tonic-gate /*
2d62bc4baSyz147064  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  *
57c478bd9Sstevel@tonic-gate  * Copyright (c) 1983, 1993
67c478bd9Sstevel@tonic-gate  *	The Regents of the University of California.  All rights reserved.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
97c478bd9Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
107c478bd9Sstevel@tonic-gate  * are met:
117c478bd9Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
127c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
137c478bd9Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
147c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in the
157c478bd9Sstevel@tonic-gate  *    documentation and/or other materials provided with the distribution.
167c478bd9Sstevel@tonic-gate  * 3. All advertising materials mentioning features or use of this software
177c478bd9Sstevel@tonic-gate  *    must display the following acknowledgment:
187c478bd9Sstevel@tonic-gate  *	This product includes software developed by the University of
197c478bd9Sstevel@tonic-gate  *	California, Berkeley and its contributors.
207c478bd9Sstevel@tonic-gate  * 4. Neither the name of the University nor the names of its contributors
217c478bd9Sstevel@tonic-gate  *    may be used to endorse or promote products derived from this software
227c478bd9Sstevel@tonic-gate  *    without specific prior written permission.
237c478bd9Sstevel@tonic-gate  *
247c478bd9Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
257c478bd9Sstevel@tonic-gate  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
267c478bd9Sstevel@tonic-gate  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
277c478bd9Sstevel@tonic-gate  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
287c478bd9Sstevel@tonic-gate  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
297c478bd9Sstevel@tonic-gate  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
307c478bd9Sstevel@tonic-gate  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
317c478bd9Sstevel@tonic-gate  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
327c478bd9Sstevel@tonic-gate  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
337c478bd9Sstevel@tonic-gate  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
347c478bd9Sstevel@tonic-gate  * SUCH DAMAGE.
357c478bd9Sstevel@tonic-gate  *
367c478bd9Sstevel@tonic-gate  * $FreeBSD: src/sbin/routed/if.c,v 1.8 2000/08/11 08:24:38 sheldonh Exp $
377c478bd9Sstevel@tonic-gate  */
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate #include "defs.h"
407c478bd9Sstevel@tonic-gate #include "pathnames.h"
417c478bd9Sstevel@tonic-gate #include <sys/sockio.h>
427c478bd9Sstevel@tonic-gate #include <inet/ip.h>
437c478bd9Sstevel@tonic-gate #include <kstat.h>
447c478bd9Sstevel@tonic-gate #include <stropts.h>
457c478bd9Sstevel@tonic-gate #include <fcntl.h>
467c478bd9Sstevel@tonic-gate #include <stddef.h>
477c478bd9Sstevel@tonic-gate #include <assert.h>
487c478bd9Sstevel@tonic-gate 
497c478bd9Sstevel@tonic-gate /* linked list of all interfaces */
507c478bd9Sstevel@tonic-gate struct interface *ifnet;
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate /*
537c478bd9Sstevel@tonic-gate  * Acceptable sizes (in number of interfaces) for the interface hash
547c478bd9Sstevel@tonic-gate  * tables.  These must all be prime.  The interface hash tables all
557c478bd9Sstevel@tonic-gate  * start with a size of hash_table_sizes[0], and increase as needed.
567c478bd9Sstevel@tonic-gate  */
577c478bd9Sstevel@tonic-gate size_t hash_table_sizes[] = { 67, 131, 257, 521, 1031, 2053, 4099, 0 };
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate struct htbl {
607c478bd9Sstevel@tonic-gate 	void		**htbl_ptrs;
617c478bd9Sstevel@tonic-gate 	uint_t		(*htbl_hash)(const void *, size_t);
627c478bd9Sstevel@tonic-gate 	size_t		htbl_link_off;	/* offset of the linkage structure */
637c478bd9Sstevel@tonic-gate 	size_t		htbl_key_off;	/* offset of the key value (rehash) */
647c478bd9Sstevel@tonic-gate 	size_t		htbl_size;	/* size of the hash */
657c478bd9Sstevel@tonic-gate 	uint_t		htbl_size_index;
667c478bd9Sstevel@tonic-gate 	uint_t		htbl_ifcount;	/* count of entries */
677c478bd9Sstevel@tonic-gate 	boolean_t	htbl_grow;	/* growth allowed */
687c478bd9Sstevel@tonic-gate };
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate /* Get first element -- for iteration */
717c478bd9Sstevel@tonic-gate #define	HFIRST(htbl, arg) \
727c478bd9Sstevel@tonic-gate 	((htbl)->htbl_ptrs[(htbl)->htbl_hash((arg), 0) % (htbl)->htbl_size])
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate /* Add an element to a hash */
757c478bd9Sstevel@tonic-gate #define	HADD(htbl, strp) \
767c478bd9Sstevel@tonic-gate 	hash_link((htbl), (htbl)->htbl_hash((strp), (htbl)->htbl_key_off), \
777c478bd9Sstevel@tonic-gate 	    (strp))
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate uint_t	tot_interfaces;			/* # of remote and local interfaces */
807c478bd9Sstevel@tonic-gate uint_t	rip_interfaces;			/* # of interfaces doing RIP */
817c478bd9Sstevel@tonic-gate uint_t	ripout_interfaces;		/* # of interfaces advertising RIP */
827c478bd9Sstevel@tonic-gate uint_t	fwd_interfaces;			/* # of interfaces ip_forwarding=1 */
837c478bd9Sstevel@tonic-gate static boolean_t foundloopback;		/* valid flag for loopaddr */
847c478bd9Sstevel@tonic-gate in_addr_t	loopaddr;		/* our address on loopback */
857c478bd9Sstevel@tonic-gate static struct	rt_spare loop_rts;
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate struct timeval ifscan_timer;
887c478bd9Sstevel@tonic-gate static struct timeval last_ifscan;
897c478bd9Sstevel@tonic-gate #define	IF_RESCAN_DELAY() \
907c478bd9Sstevel@tonic-gate 	(last_ifscan.tv_sec == now.tv_sec && \
917c478bd9Sstevel@tonic-gate 	    last_ifscan.tv_usec == now.tv_usec && \
927c478bd9Sstevel@tonic-gate 	    timercmp(&ifscan_timer, &now, > /* */))
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate boolean_t		have_ripv1_out;	/* have a RIPv1 interface */
957c478bd9Sstevel@tonic-gate static boolean_t	have_ripv1_in;
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate static void		if_bad(struct interface *, boolean_t);
987c478bd9Sstevel@tonic-gate static boolean_t	addrouteforif(struct interface *);
997c478bd9Sstevel@tonic-gate static int	get_if_kstats(struct interface *, struct phyi_data *);
1007c478bd9Sstevel@tonic-gate static uint_t	ahash(const void *, uint_t);
1017c478bd9Sstevel@tonic-gate static uint_t	ihash(const void *, uint_t);
1027c478bd9Sstevel@tonic-gate static uint_t	nhash(const void *, uint_t);
1037c478bd9Sstevel@tonic-gate static void	htbl_grow(struct htbl *);
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate /*
1067c478bd9Sstevel@tonic-gate  * Table of all interfaces, hashed by interface address.  For remote
1077c478bd9Sstevel@tonic-gate  * interfaces, the gateway address is used.
1087c478bd9Sstevel@tonic-gate  */
1097c478bd9Sstevel@tonic-gate static struct htbl ahash_tbl = {
1107c478bd9Sstevel@tonic-gate     NULL, ahash, offsetof(struct interface, int_ahash),
1117c478bd9Sstevel@tonic-gate     offsetof(struct interface, int_addr),
1127c478bd9Sstevel@tonic-gate     0, 0, 0, _B_TRUE };
1137c478bd9Sstevel@tonic-gate /*
1147c478bd9Sstevel@tonic-gate  * Table of broadcast capable interfaces, hashed by interface broadcast
1157c478bd9Sstevel@tonic-gate  * address.
1167c478bd9Sstevel@tonic-gate  */
1177c478bd9Sstevel@tonic-gate static struct htbl bhash_tbl = {
1187c478bd9Sstevel@tonic-gate     NULL, ahash, offsetof(struct interface, int_bhash),
1197c478bd9Sstevel@tonic-gate     offsetof(struct interface, int_brdaddr),
1207c478bd9Sstevel@tonic-gate     0, 0, 0, _B_TRUE };
1217c478bd9Sstevel@tonic-gate /*
1227c478bd9Sstevel@tonic-gate  * Table of physical_interface structures (lists of interfaces by ifIndex),
1237c478bd9Sstevel@tonic-gate  * hashed by interface index.
1247c478bd9Sstevel@tonic-gate  */
1257c478bd9Sstevel@tonic-gate static struct htbl ihash_tbl = {
1267c478bd9Sstevel@tonic-gate     NULL, ihash, offsetof(struct physical_interface, phyi_link),
1277c478bd9Sstevel@tonic-gate     offsetof(struct physical_interface, phyi_index),
1287c478bd9Sstevel@tonic-gate     0, 0, 0, _B_TRUE };
1297c478bd9Sstevel@tonic-gate /*
1307c478bd9Sstevel@tonic-gate  * Table of all interfaces, hashed by interface name.
1317c478bd9Sstevel@tonic-gate  */
1327c478bd9Sstevel@tonic-gate static struct htbl nhash_tbl = {
1337c478bd9Sstevel@tonic-gate     NULL, nhash, offsetof(struct interface, int_nhash),
1347c478bd9Sstevel@tonic-gate     offsetof(struct interface, int_name),
1357c478bd9Sstevel@tonic-gate     0, 0, 0, _B_TRUE };
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate static struct physical_interface dummy_phyi;
1387c478bd9Sstevel@tonic-gate struct interface dummy_ifp;
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate /* Hash based on an IP address. */
1417c478bd9Sstevel@tonic-gate static uint_t
ahash(const void * arg,size_t voffs)1427c478bd9Sstevel@tonic-gate ahash(const void *arg, size_t voffs)
1437c478bd9Sstevel@tonic-gate {
1447c478bd9Sstevel@tonic-gate 	/* LINTED */
1457c478bd9Sstevel@tonic-gate 	return ((uint_t)*(const in_addr_t *)((const char *)arg + voffs));
1467c478bd9Sstevel@tonic-gate }
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate static uint_t
ihash(const void * arg,size_t voffs)1497c478bd9Sstevel@tonic-gate ihash(const void *arg, size_t voffs)
1507c478bd9Sstevel@tonic-gate {
1517c478bd9Sstevel@tonic-gate 	/* LINTED */
1527c478bd9Sstevel@tonic-gate 	return ((uint_t)*(const uint32_t *)((const char *)arg + voffs));
1537c478bd9Sstevel@tonic-gate }
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate static uint_t
nhash(const void * arg,size_t voffs)1567c478bd9Sstevel@tonic-gate nhash(const void *arg, size_t voffs)
1577c478bd9Sstevel@tonic-gate {
1587c478bd9Sstevel@tonic-gate 	const char *cp = (const char *)arg + voffs;
1597c478bd9Sstevel@tonic-gate 	uint_t i;
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate 	for (i = 0; *cp != '\0'; cp++) {
1627c478bd9Sstevel@tonic-gate 		i = ((i<<1) & 0x7fffffff) | ((i>>30) & 0x00000003);
1637c478bd9Sstevel@tonic-gate 		i ^= *cp;
1647c478bd9Sstevel@tonic-gate 	}
1657c478bd9Sstevel@tonic-gate 	return (i);
1667c478bd9Sstevel@tonic-gate }
1677c478bd9Sstevel@tonic-gate 
1687c478bd9Sstevel@tonic-gate /*
1697c478bd9Sstevel@tonic-gate  * Add an element to the head of the list.
1707c478bd9Sstevel@tonic-gate  */
1717c478bd9Sstevel@tonic-gate static void
link_in(void ** head,void * strp,size_t loffs)1727c478bd9Sstevel@tonic-gate link_in(void **head, void *strp, size_t loffs)
1737c478bd9Sstevel@tonic-gate {
1747c478bd9Sstevel@tonic-gate 	struct hlinkage *hlp;
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	/* LINTED: alignment known to be good. */
1777c478bd9Sstevel@tonic-gate 	hlp = (struct hlinkage *)((char *)strp + loffs);
1787c478bd9Sstevel@tonic-gate 	hlp->hl_prev = head;
1797c478bd9Sstevel@tonic-gate 	if ((hlp->hl_next = *head) != NULL) {
1807c478bd9Sstevel@tonic-gate 		/* LINTED */
1817c478bd9Sstevel@tonic-gate 		((struct hlinkage *)((char *)*head + loffs))->hl_prev =
1827c478bd9Sstevel@tonic-gate 		    &hlp->hl_next;
1837c478bd9Sstevel@tonic-gate 	}
1847c478bd9Sstevel@tonic-gate 	*head = strp;
1857c478bd9Sstevel@tonic-gate }
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate /* Remove from a list */
1887c478bd9Sstevel@tonic-gate static void
link_out(void * strp,size_t loffs)1897c478bd9Sstevel@tonic-gate link_out(void *strp, size_t loffs)
1907c478bd9Sstevel@tonic-gate {
1917c478bd9Sstevel@tonic-gate 	struct hlinkage *hlp;
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate 	/* LINTED: alignment known to be good. */
1947c478bd9Sstevel@tonic-gate 	hlp = (struct hlinkage *)((char *)strp + loffs);
1957c478bd9Sstevel@tonic-gate 	if ((*hlp->hl_prev = hlp->hl_next) != NULL) {
1967c478bd9Sstevel@tonic-gate 		/* LINTED */
1977c478bd9Sstevel@tonic-gate 		((struct hlinkage *)((char *)hlp->hl_next + loffs))->hl_prev =
1987c478bd9Sstevel@tonic-gate 		    hlp->hl_prev;
1997c478bd9Sstevel@tonic-gate 	}
2007c478bd9Sstevel@tonic-gate }
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate /* Add to a hash */
2037c478bd9Sstevel@tonic-gate static void
hash_link(struct htbl * htbl,uint_t hval,void * strp)2047c478bd9Sstevel@tonic-gate hash_link(struct htbl *htbl, uint_t hval, void *strp)
2057c478bd9Sstevel@tonic-gate {
2067c478bd9Sstevel@tonic-gate 	void **hep;
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 	if (htbl->htbl_grow && htbl->htbl_ifcount >= htbl->htbl_size * 5)
2097c478bd9Sstevel@tonic-gate 		htbl_grow(htbl);
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate 	hep = &htbl->htbl_ptrs[hval % htbl->htbl_size];
2127c478bd9Sstevel@tonic-gate 	link_in(hep, strp, htbl->htbl_link_off);
2137c478bd9Sstevel@tonic-gate 	htbl->htbl_ifcount++;
2147c478bd9Sstevel@tonic-gate }
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate /* Remove from a hash */
2177c478bd9Sstevel@tonic-gate static void
hash_unlink(struct htbl * htbl,void * strp)2187c478bd9Sstevel@tonic-gate hash_unlink(struct htbl *htbl, void *strp)
2197c478bd9Sstevel@tonic-gate {
2207c478bd9Sstevel@tonic-gate 	link_out(strp, htbl->htbl_link_off);
2217c478bd9Sstevel@tonic-gate 	htbl->htbl_ifcount--;
2227c478bd9Sstevel@tonic-gate }
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate static void
dummy_ifp_init(void)2257c478bd9Sstevel@tonic-gate dummy_ifp_init(void)
2267c478bd9Sstevel@tonic-gate {
2277c478bd9Sstevel@tonic-gate 	dummy_phyi.phyi_interface = &dummy_ifp;
2287c478bd9Sstevel@tonic-gate 	dummy_ifp.int_phys = &dummy_phyi;
2297c478bd9Sstevel@tonic-gate 	(void) strcpy(dummy_phyi.phyi_name, "wildcard");
2307c478bd9Sstevel@tonic-gate 	(void) strcpy(dummy_ifp.int_name, "wildcard");
2317c478bd9Sstevel@tonic-gate 	dummy_ifp.int_dstaddr = dummy_ifp.int_addr = INADDR_NONE;
2327c478bd9Sstevel@tonic-gate 	dummy_ifp.int_mask = IP_HOST_MASK;
2337c478bd9Sstevel@tonic-gate 	dummy_ifp.int_metric = HOPCNT_INFINITY;
2347c478bd9Sstevel@tonic-gate 	dummy_ifp.int_state = (IS_BROKE|IS_PASSIVE|IS_NO_RIP|IS_NO_RDISC);
2357c478bd9Sstevel@tonic-gate 	dummy_ifp.int_std_mask = std_mask(dummy_ifp.int_addr);
2367c478bd9Sstevel@tonic-gate 	dummy_ifp.int_std_net = dummy_ifp.int_net & dummy_ifp.int_std_mask;
2377c478bd9Sstevel@tonic-gate 	dummy_ifp.int_std_addr = htonl(dummy_ifp.int_std_net);
2387c478bd9Sstevel@tonic-gate }
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate /* allocate the interface hash tables */
2417c478bd9Sstevel@tonic-gate void
iftbl_alloc(void)2427c478bd9Sstevel@tonic-gate iftbl_alloc(void)
2437c478bd9Sstevel@tonic-gate {
2447c478bd9Sstevel@tonic-gate 	size_t initial_size = hash_table_sizes[0];
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate 	errno = 0;
2477c478bd9Sstevel@tonic-gate 	ahash_tbl.htbl_ptrs = calloc(initial_size, sizeof (void *));
2487c478bd9Sstevel@tonic-gate 	bhash_tbl.htbl_ptrs = calloc(initial_size, sizeof (void *));
2497c478bd9Sstevel@tonic-gate 	ihash_tbl.htbl_ptrs = calloc(initial_size, sizeof (void *));
2507c478bd9Sstevel@tonic-gate 	nhash_tbl.htbl_ptrs = calloc(initial_size, sizeof (void *));
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 	if (errno != 0)
2537c478bd9Sstevel@tonic-gate 		BADERR(_B_FALSE, "Unable to allocate interface tables");
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate 	ahash_tbl.htbl_size = initial_size;
2567c478bd9Sstevel@tonic-gate 	bhash_tbl.htbl_size = initial_size;
2577c478bd9Sstevel@tonic-gate 	ihash_tbl.htbl_size = initial_size;
2587c478bd9Sstevel@tonic-gate 	nhash_tbl.htbl_size = initial_size;
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate 	dummy_ifp_init();
2617c478bd9Sstevel@tonic-gate }
2627c478bd9Sstevel@tonic-gate 
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate static void
htbl_grow(struct htbl * htbl)2657c478bd9Sstevel@tonic-gate htbl_grow(struct htbl *htbl)
2667c478bd9Sstevel@tonic-gate {
2677c478bd9Sstevel@tonic-gate 	void *strp;
2687c478bd9Sstevel@tonic-gate 	void **new_ptrs, **saved_old_ptrs, **old_ptrs;
2697c478bd9Sstevel@tonic-gate 	size_t new_size, old_size;
2707c478bd9Sstevel@tonic-gate 	static uint_t failed_count;
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 	if ((new_size = hash_table_sizes[htbl->htbl_size_index + 1]) == 0)
2737c478bd9Sstevel@tonic-gate 		return;
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 	if ((new_ptrs = calloc(new_size, sizeof (void *))) == NULL) {
2767c478bd9Sstevel@tonic-gate 		/*
2777c478bd9Sstevel@tonic-gate 		 * This is not fatal since we already have a
2787c478bd9Sstevel@tonic-gate 		 * functional, yet crowded, interface table.
2797c478bd9Sstevel@tonic-gate 		 */
2807c478bd9Sstevel@tonic-gate 		if (++failed_count % 100 == 1)
2817c478bd9Sstevel@tonic-gate 			msglog("%sunable to grow interface hash table: %s",
2827c478bd9Sstevel@tonic-gate 			    failed_count > 1 ? "Still " : "",
2837c478bd9Sstevel@tonic-gate 			    rip_strerror(errno));
2847c478bd9Sstevel@tonic-gate 		return;
2857c478bd9Sstevel@tonic-gate 	}
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate 	failed_count = 0;
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 	saved_old_ptrs = old_ptrs = htbl->htbl_ptrs;
2907c478bd9Sstevel@tonic-gate 	old_size = htbl->htbl_size;
2917c478bd9Sstevel@tonic-gate 	htbl->htbl_ptrs = new_ptrs;
2927c478bd9Sstevel@tonic-gate 	htbl->htbl_size = new_size;
2937c478bd9Sstevel@tonic-gate 	htbl->htbl_size_index++;
2947c478bd9Sstevel@tonic-gate 	htbl->htbl_ifcount = 0;
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate 	/*
2977c478bd9Sstevel@tonic-gate 	 * Go through the list of structures, and re-link each into
2987c478bd9Sstevel@tonic-gate 	 * this new table.
2997c478bd9Sstevel@tonic-gate 	 */
3007c478bd9Sstevel@tonic-gate 	htbl->htbl_grow = _B_FALSE;
3017c478bd9Sstevel@tonic-gate 	while (old_size-- > 0) {
3027c478bd9Sstevel@tonic-gate 		strp = *old_ptrs++;
3037c478bd9Sstevel@tonic-gate 		HADD(htbl, strp);
3047c478bd9Sstevel@tonic-gate 	}
3057c478bd9Sstevel@tonic-gate 
3067c478bd9Sstevel@tonic-gate 	htbl->htbl_grow = _B_TRUE;
3077c478bd9Sstevel@tonic-gate 	free(saved_old_ptrs);
3087c478bd9Sstevel@tonic-gate }
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate /* Link a new interface into the lists and hash tables. */
3117c478bd9Sstevel@tonic-gate void
if_link(struct interface * ifp,uint32_t ifindex)3127c478bd9Sstevel@tonic-gate if_link(struct interface *ifp, uint32_t ifindex)
3137c478bd9Sstevel@tonic-gate {
3147c478bd9Sstevel@tonic-gate 	struct physical_interface *phyi;
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 	link_in((void **)&ifnet, ifp, offsetof(struct interface, int_link));
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate 	HADD(&ahash_tbl, ifp);
3197c478bd9Sstevel@tonic-gate 	HADD(&nhash_tbl, ifp);
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 	if (ifp->int_if_flags & IFF_BROADCAST)
3227c478bd9Sstevel@tonic-gate 		HADD(&bhash_tbl, ifp);
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 	if (ifindex != 0) {
3257c478bd9Sstevel@tonic-gate 		for (phyi = HFIRST(&ihash_tbl, &ifindex);
3267c478bd9Sstevel@tonic-gate 		    phyi != NULL; phyi = phyi->phyi_link.hl_next) {
3277c478bd9Sstevel@tonic-gate 			if (phyi->phyi_index == ifindex)
3287c478bd9Sstevel@tonic-gate 				break;
3297c478bd9Sstevel@tonic-gate 		}
3307c478bd9Sstevel@tonic-gate 		if (phyi == NULL) {
3317c478bd9Sstevel@tonic-gate 			size_t size;
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 			phyi = rtmalloc(sizeof (*phyi), "physical_interface");
3347c478bd9Sstevel@tonic-gate 			(void) memset(phyi, 0, sizeof (*phyi));
3357c478bd9Sstevel@tonic-gate 			phyi->phyi_index = ifindex;
3367c478bd9Sstevel@tonic-gate 			/* LINTED */
3377c478bd9Sstevel@tonic-gate 			assert(IF_NAME_LEN >= IF_NAMESIZE);
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate 			size = strcspn(ifp->int_name, ":");
3407c478bd9Sstevel@tonic-gate 			(void) strncpy(phyi->phyi_name, ifp->int_name,
3417c478bd9Sstevel@tonic-gate 			    size);
3427c478bd9Sstevel@tonic-gate 			phyi->phyi_name[size] = '\0';
3437c478bd9Sstevel@tonic-gate 			HADD(&ihash_tbl, phyi);
3447c478bd9Sstevel@tonic-gate 		}
3457c478bd9Sstevel@tonic-gate 		link_in((void **)&phyi->phyi_interface, ifp,
3467c478bd9Sstevel@tonic-gate 		    offsetof(struct interface, int_ilist));
3477c478bd9Sstevel@tonic-gate 		ifp->int_phys = phyi;
3487c478bd9Sstevel@tonic-gate 	}
3497c478bd9Sstevel@tonic-gate }
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate /* Find the interface with an address */
3527c478bd9Sstevel@tonic-gate struct interface *
ifwithaddr(in_addr_t addr,boolean_t bcast,boolean_t remote)3537c478bd9Sstevel@tonic-gate ifwithaddr(in_addr_t addr,
3547c478bd9Sstevel@tonic-gate     boolean_t bcast,	/* notice IFF_BROADCAST address */
3557c478bd9Sstevel@tonic-gate     boolean_t remote)	/* include IS_REMOTE interfaces */
3567c478bd9Sstevel@tonic-gate {
3577c478bd9Sstevel@tonic-gate 	struct interface *ifp, *possible = NULL;
3587c478bd9Sstevel@tonic-gate 	uint32_t remote_state;
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 	remote_state = (!remote ? IS_REMOTE : 0);
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 	for (ifp = HFIRST(&ahash_tbl, &addr); ifp != NULL;
3637c478bd9Sstevel@tonic-gate 	    ifp = ifp->int_ahash.hl_next) {
3647c478bd9Sstevel@tonic-gate 		if (ifp->int_addr != addr)
3657c478bd9Sstevel@tonic-gate 			continue;
3667c478bd9Sstevel@tonic-gate 		if (ifp->int_state & remote_state)
3677c478bd9Sstevel@tonic-gate 			continue;
3687c478bd9Sstevel@tonic-gate 		if (!(ifp->int_state & (IS_BROKE | IS_PASSIVE)))
3697c478bd9Sstevel@tonic-gate 			return (ifp);
3707c478bd9Sstevel@tonic-gate 		possible = ifp;
3717c478bd9Sstevel@tonic-gate 	}
3727c478bd9Sstevel@tonic-gate 
3737c478bd9Sstevel@tonic-gate 	if (possible != NULL || !bcast)
3747c478bd9Sstevel@tonic-gate 		return (possible);
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 	for (ifp = HFIRST(&bhash_tbl, &addr); ifp != NULL;
3777c478bd9Sstevel@tonic-gate 	    ifp = ifp->int_bhash.hl_next) {
3787c478bd9Sstevel@tonic-gate 		if (ifp->int_brdaddr != addr)
3797c478bd9Sstevel@tonic-gate 			continue;
3807c478bd9Sstevel@tonic-gate 		if (ifp->int_state & remote_state)
3817c478bd9Sstevel@tonic-gate 			continue;
3827c478bd9Sstevel@tonic-gate 		if (!(ifp->int_state & (IS_BROKE | IS_PASSIVE)))
3837c478bd9Sstevel@tonic-gate 			return (ifp);
3847c478bd9Sstevel@tonic-gate 		possible = ifp;
3857c478bd9Sstevel@tonic-gate 	}
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate 	return (possible);
3887c478bd9Sstevel@tonic-gate }
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate /* find the interface with the specified name ("hme0" for example) */
3927c478bd9Sstevel@tonic-gate struct interface *
ifwithname(const char * name)3937c478bd9Sstevel@tonic-gate ifwithname(const char *name)
3947c478bd9Sstevel@tonic-gate {
3957c478bd9Sstevel@tonic-gate 	struct interface *ifp;
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 	for (;;) {
3987c478bd9Sstevel@tonic-gate 		for (ifp = HFIRST(&nhash_tbl, name); ifp != NULL;
3997c478bd9Sstevel@tonic-gate 		    ifp = ifp->int_nhash.hl_next) {
4007c478bd9Sstevel@tonic-gate 			if (strcmp(ifp->int_name, name) == 0)
4017c478bd9Sstevel@tonic-gate 				return (ifp);
4027c478bd9Sstevel@tonic-gate 		}
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate 		/*
4057c478bd9Sstevel@tonic-gate 		 * If there is no known interface, maybe there is a
4067c478bd9Sstevel@tonic-gate 		 * new interface.  So just once look for new interfaces.
4077c478bd9Sstevel@tonic-gate 		 */
4087c478bd9Sstevel@tonic-gate 		if (IF_RESCAN_DELAY())
4097c478bd9Sstevel@tonic-gate 			return (NULL);
4107c478bd9Sstevel@tonic-gate 		ifscan();
4117c478bd9Sstevel@tonic-gate 	}
4127c478bd9Sstevel@tonic-gate }
4137c478bd9Sstevel@tonic-gate 
414*982ec2c2SRishi Srivatsavai /* Return physical interface with the specified name */
415*982ec2c2SRishi Srivatsavai struct physical_interface *
phys_byname(const char * name)416*982ec2c2SRishi Srivatsavai phys_byname(const char *name)
417*982ec2c2SRishi Srivatsavai {
418*982ec2c2SRishi Srivatsavai 	int nlen;
419*982ec2c2SRishi Srivatsavai 	size_t i;
420*982ec2c2SRishi Srivatsavai 	struct physical_interface *phyi;
421*982ec2c2SRishi Srivatsavai 
422*982ec2c2SRishi Srivatsavai 	nlen = strcspn(name, ":");
423*982ec2c2SRishi Srivatsavai 	for (i = 0; i < ihash_tbl.htbl_size; i++) {
424*982ec2c2SRishi Srivatsavai 		for (phyi = ihash_tbl.htbl_ptrs[i]; phyi != NULL;
425*982ec2c2SRishi Srivatsavai 		    phyi = phyi->phyi_link.hl_next) {
426*982ec2c2SRishi Srivatsavai 			if (strncmp(phyi->phyi_name, name, nlen) == 0 &&
427*982ec2c2SRishi Srivatsavai 			    phyi->phyi_name[nlen] == '\0')
428*982ec2c2SRishi Srivatsavai 				return (phyi);
429*982ec2c2SRishi Srivatsavai 		}
430*982ec2c2SRishi Srivatsavai 	}
431*982ec2c2SRishi Srivatsavai 	return (NULL);
432*982ec2c2SRishi Srivatsavai }
433*982ec2c2SRishi Srivatsavai 
4347c478bd9Sstevel@tonic-gate struct interface *
findremoteif(in_addr_t addr)4357c478bd9Sstevel@tonic-gate findremoteif(in_addr_t addr)
4367c478bd9Sstevel@tonic-gate {
4377c478bd9Sstevel@tonic-gate 	struct interface *ifp;
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate 	for (ifp = HFIRST(&ahash_tbl, &addr); ifp != NULL;
4407c478bd9Sstevel@tonic-gate 	    ifp = ifp->int_ahash.hl_next) {
4417c478bd9Sstevel@tonic-gate 		if ((ifp->int_state & IS_REMOTE) && ifp->int_addr == addr)
4427c478bd9Sstevel@tonic-gate 			return (ifp);
4437c478bd9Sstevel@tonic-gate 	}
4447c478bd9Sstevel@tonic-gate 
4457c478bd9Sstevel@tonic-gate 	return (NULL);
4467c478bd9Sstevel@tonic-gate }
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate struct interface *
findifaddr(in_addr_t addr)4497c478bd9Sstevel@tonic-gate findifaddr(in_addr_t addr)
4507c478bd9Sstevel@tonic-gate {
4517c478bd9Sstevel@tonic-gate 	struct interface *ifp;
4527c478bd9Sstevel@tonic-gate 
4537c478bd9Sstevel@tonic-gate 	for (ifp = HFIRST(&ahash_tbl, &addr); ifp != NULL;
4547c478bd9Sstevel@tonic-gate 	    ifp = ifp->int_ahash.hl_next) {
4557c478bd9Sstevel@tonic-gate 		if (ifp->int_addr == addr)
4567c478bd9Sstevel@tonic-gate 			return (ifp);
4577c478bd9Sstevel@tonic-gate 	}
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 	return (NULL);
4607c478bd9Sstevel@tonic-gate }
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate /*
4637c478bd9Sstevel@tonic-gate  * Return the first interface with the given index.
4647c478bd9Sstevel@tonic-gate  */
4657c478bd9Sstevel@tonic-gate struct interface *
ifwithindex(ulong_t index,boolean_t rescan_ok)4667c478bd9Sstevel@tonic-gate ifwithindex(ulong_t index,
4677c478bd9Sstevel@tonic-gate     boolean_t rescan_ok)
4687c478bd9Sstevel@tonic-gate {
4697c478bd9Sstevel@tonic-gate 	struct physical_interface *phyi;
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 	for (;;) {
4727c478bd9Sstevel@tonic-gate 		for (phyi = HFIRST(&ihash_tbl, &index); phyi != NULL;
4737c478bd9Sstevel@tonic-gate 		    phyi = phyi->phyi_link.hl_next) {
4747c478bd9Sstevel@tonic-gate 			if (phyi->phyi_index == index)
4757c478bd9Sstevel@tonic-gate 				return (phyi->phyi_interface);
4767c478bd9Sstevel@tonic-gate 		}
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate 		/*
4797c478bd9Sstevel@tonic-gate 		 * If there is no known interface, maybe there is a
4807c478bd9Sstevel@tonic-gate 		 * new interface.  So just once look for new interfaces.
4817c478bd9Sstevel@tonic-gate 		 */
4827c478bd9Sstevel@tonic-gate 		if (!rescan_ok || IF_RESCAN_DELAY())
4837c478bd9Sstevel@tonic-gate 			return (NULL);
4847c478bd9Sstevel@tonic-gate 		rescan_ok = _B_FALSE;
4857c478bd9Sstevel@tonic-gate 		ifscan();
4867c478bd9Sstevel@tonic-gate 	}
4877c478bd9Sstevel@tonic-gate }
4887c478bd9Sstevel@tonic-gate 
489*982ec2c2SRishi Srivatsavai /*
490*982ec2c2SRishi Srivatsavai  * Returns true only if given ifp has the exact address else returns
491*982ec2c2SRishi Srivatsavai  * false and sets best if an ifp matches partially and is a better
492*982ec2c2SRishi Srivatsavai  * match than the previous one passed via best.
493*982ec2c2SRishi Srivatsavai  */
494*982ec2c2SRishi Srivatsavai boolean_t
addr_on_ifp(in_addr_t addr,struct interface * ifp,struct interface ** best)495*982ec2c2SRishi Srivatsavai addr_on_ifp(in_addr_t addr, struct interface *ifp,
496*982ec2c2SRishi Srivatsavai     struct interface **best)
497*982ec2c2SRishi Srivatsavai {
498*982ec2c2SRishi Srivatsavai 	struct interface *p_best = *best;
499*982ec2c2SRishi Srivatsavai 
500*982ec2c2SRishi Srivatsavai 	/*
501*982ec2c2SRishi Srivatsavai 	 * Don't use a duplicate interface since it is unusable for output.
502*982ec2c2SRishi Srivatsavai 	 */
503*982ec2c2SRishi Srivatsavai 	if (ifp->int_state & IS_DUP)
504*982ec2c2SRishi Srivatsavai 		return (_B_FALSE);
505*982ec2c2SRishi Srivatsavai 
506*982ec2c2SRishi Srivatsavai 	if (ifp->int_if_flags & IFF_POINTOPOINT) {
507*982ec2c2SRishi Srivatsavai 		if (ifp->int_dstaddr == addr) {
508*982ec2c2SRishi Srivatsavai 			*best = NULL;
509*982ec2c2SRishi Srivatsavai 			return (_B_TRUE);
510*982ec2c2SRishi Srivatsavai 		}
511*982ec2c2SRishi Srivatsavai 	} else {
512*982ec2c2SRishi Srivatsavai 		if (ifp->int_addr == addr) {
513*982ec2c2SRishi Srivatsavai 			if (IS_PASSIVE_IFP(ifp))
514*982ec2c2SRishi Srivatsavai 				trace_misc("addr_on_ifp "
515*982ec2c2SRishi Srivatsavai 				    "returning passive intf %s",
516*982ec2c2SRishi Srivatsavai 				    ifp->int_name);
517*982ec2c2SRishi Srivatsavai 			*best = NULL;
518*982ec2c2SRishi Srivatsavai 			return (_B_TRUE);
519*982ec2c2SRishi Srivatsavai 		}
520*982ec2c2SRishi Srivatsavai 
521*982ec2c2SRishi Srivatsavai 		/* Look for the longest approximate match. */
522*982ec2c2SRishi Srivatsavai 		if (on_net(addr, ifp->int_net, ifp->int_mask) &&
523*982ec2c2SRishi Srivatsavai 		    (p_best == NULL ||
524*982ec2c2SRishi Srivatsavai 		    ifp->int_mask > p_best->int_mask)) {
525*982ec2c2SRishi Srivatsavai 			*best = ifp;
526*982ec2c2SRishi Srivatsavai 		}
527*982ec2c2SRishi Srivatsavai 	}
528*982ec2c2SRishi Srivatsavai 	return (_B_FALSE);
529*982ec2c2SRishi Srivatsavai }
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate /*
5327c478bd9Sstevel@tonic-gate  * Find an interface which should be receiving packets sent from the
5337c478bd9Sstevel@tonic-gate  * given address.  Used as a last ditch effort for figuring out which
5347c478bd9Sstevel@tonic-gate  * interface a packet came in on.  Also used for finding out which
5357c478bd9Sstevel@tonic-gate  * interface points towards the gateway of static routes learned from
5367c478bd9Sstevel@tonic-gate  * the kernel.
5377c478bd9Sstevel@tonic-gate  */
5387c478bd9Sstevel@tonic-gate struct interface *
iflookup(in_addr_t addr)5397c478bd9Sstevel@tonic-gate iflookup(in_addr_t addr)
5407c478bd9Sstevel@tonic-gate {
5417c478bd9Sstevel@tonic-gate 	struct interface *ifp, *maybe;
5427c478bd9Sstevel@tonic-gate 
5437c478bd9Sstevel@tonic-gate 	maybe = NULL;
5447c478bd9Sstevel@tonic-gate 	for (;;) {
5457c478bd9Sstevel@tonic-gate 		for (ifp = ifnet; ifp != NULL; ifp = ifp->int_next) {
5467c478bd9Sstevel@tonic-gate 
547*982ec2c2SRishi Srivatsavai 			/* Exact match found */
548*982ec2c2SRishi Srivatsavai 			if (addr_on_ifp(addr, ifp, &maybe))
5497c478bd9Sstevel@tonic-gate 				return (ifp);
550f9aa3e1eSkcpoon 		}
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate 		/*
5537c478bd9Sstevel@tonic-gate 		 * If there is no known interface, maybe there is a
5547c478bd9Sstevel@tonic-gate 		 * new interface.  So just once look for new interfaces.
5557c478bd9Sstevel@tonic-gate 		 */
5567c478bd9Sstevel@tonic-gate 		if (maybe == NULL && !IF_RESCAN_DELAY())
5577c478bd9Sstevel@tonic-gate 			ifscan();
5587c478bd9Sstevel@tonic-gate 		else
5597c478bd9Sstevel@tonic-gate 			break;
5607c478bd9Sstevel@tonic-gate 	}
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate 	if (maybe != NULL && IS_PASSIVE_IFP(maybe)) {
5637c478bd9Sstevel@tonic-gate 		trace_misc("iflookup returning passive intf %s",
5647c478bd9Sstevel@tonic-gate 		    maybe->int_name);
5657c478bd9Sstevel@tonic-gate 	}
5667c478bd9Sstevel@tonic-gate 	return (maybe);
5677c478bd9Sstevel@tonic-gate }
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate /*
5707c478bd9Sstevel@tonic-gate  * Find the netmask that would be inferred by RIPv1 listeners
5717c478bd9Sstevel@tonic-gate  *	on the given interface for a given network.
5727c478bd9Sstevel@tonic-gate  *	If no interface is specified, look for the best fitting	interface.
5737c478bd9Sstevel@tonic-gate  */
5747c478bd9Sstevel@tonic-gate in_addr_t
ripv1_mask_net(in_addr_t addr,const struct interface * ifp)5757c478bd9Sstevel@tonic-gate ripv1_mask_net(in_addr_t addr,	/* in network byte order */
5767c478bd9Sstevel@tonic-gate     const struct interface *ifp)	/* as seen on this interface */
5777c478bd9Sstevel@tonic-gate {
5787c478bd9Sstevel@tonic-gate 	const struct r1net *r1p;
5797c478bd9Sstevel@tonic-gate 	in_addr_t mask = 0;
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate 	if (addr == 0)			/* default always has 0 mask */
5827c478bd9Sstevel@tonic-gate 		return (mask);
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate 	if (ifp != NULL && ifp->int_ripv1_mask != HOST_MASK) {
5857c478bd9Sstevel@tonic-gate 		/*
5867c478bd9Sstevel@tonic-gate 		 * If the target network is that of the associated interface
5877c478bd9Sstevel@tonic-gate 		 * on which it arrived, then use the netmask of the interface.
5887c478bd9Sstevel@tonic-gate 		 */
5897c478bd9Sstevel@tonic-gate 		if (on_net(addr, ifp->int_net, ifp->int_std_mask))
5907c478bd9Sstevel@tonic-gate 			mask = ifp->int_ripv1_mask;
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate 	} else {
5937c478bd9Sstevel@tonic-gate 		/*
5947c478bd9Sstevel@tonic-gate 		 * Examine all interfaces, and if it the target seems
5957c478bd9Sstevel@tonic-gate 		 * to have the same network number of an interface, use the
5967c478bd9Sstevel@tonic-gate 		 * netmask of that interface.  If there is more than one
5977c478bd9Sstevel@tonic-gate 		 * such interface, prefer the interface with the longest
5987c478bd9Sstevel@tonic-gate 		 * match.
5997c478bd9Sstevel@tonic-gate 		 */
6007c478bd9Sstevel@tonic-gate 		for (ifp = ifnet; ifp != NULL; ifp = ifp->int_next) {
6017c478bd9Sstevel@tonic-gate 			if (on_net(addr, ifp->int_std_net, ifp->int_std_mask) &&
6027c478bd9Sstevel@tonic-gate 			    ifp->int_ripv1_mask > mask &&
6037c478bd9Sstevel@tonic-gate 			    ifp->int_ripv1_mask != HOST_MASK)
6047c478bd9Sstevel@tonic-gate 				mask = ifp->int_ripv1_mask;
6057c478bd9Sstevel@tonic-gate 		}
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate 	}
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 	if (mask == 0) {
6107c478bd9Sstevel@tonic-gate 		/*
6117c478bd9Sstevel@tonic-gate 		 * Check to see if the user has supplied an applicable
6127c478bd9Sstevel@tonic-gate 		 * netmask as a ripv1_mask option in /etc/gateways.
6137c478bd9Sstevel@tonic-gate 		 */
6147c478bd9Sstevel@tonic-gate 		for (r1p = r1nets; r1p != NULL; r1p = r1p->r1net_next) {
6157c478bd9Sstevel@tonic-gate 			/*
6167c478bd9Sstevel@tonic-gate 			 * If the address is is on a matching network
6177c478bd9Sstevel@tonic-gate 			 * and we haven't already found a longer match,
6187c478bd9Sstevel@tonic-gate 			 * use the matching netmask.
6197c478bd9Sstevel@tonic-gate 			 */
6207c478bd9Sstevel@tonic-gate 			if (on_net(addr, r1p->r1net_net, r1p->r1net_match) &&
6217c478bd9Sstevel@tonic-gate 			    r1p->r1net_mask > mask)
6227c478bd9Sstevel@tonic-gate 				mask = r1p->r1net_mask;
6237c478bd9Sstevel@tonic-gate 		}
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate 		/* Otherwise, make the classic A/B/C guess. */
6267c478bd9Sstevel@tonic-gate 		if (mask == 0)
6277c478bd9Sstevel@tonic-gate 			mask = std_mask(addr);
6287c478bd9Sstevel@tonic-gate 	}
6297c478bd9Sstevel@tonic-gate 
6307c478bd9Sstevel@tonic-gate 	return (mask);
6317c478bd9Sstevel@tonic-gate }
6327c478bd9Sstevel@tonic-gate 
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate in_addr_t
ripv1_mask_host(in_addr_t addr,const struct interface * ifp)6357c478bd9Sstevel@tonic-gate ripv1_mask_host(in_addr_t addr,		/* in network byte order */
6367c478bd9Sstevel@tonic-gate     const struct interface *ifp)	/* as seen on this interface */
6377c478bd9Sstevel@tonic-gate {
6387c478bd9Sstevel@tonic-gate 	in_addr_t mask = ripv1_mask_net(addr, ifp);
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate 	/*
6427c478bd9Sstevel@tonic-gate 	 * If the computed netmask does not mask all of the set bits
6437c478bd9Sstevel@tonic-gate 	 * in the address, then assume it is a host address
6447c478bd9Sstevel@tonic-gate 	 */
6457c478bd9Sstevel@tonic-gate 	if ((ntohl(addr) & ~mask) != 0)
6467c478bd9Sstevel@tonic-gate 		mask = HOST_MASK;
6477c478bd9Sstevel@tonic-gate 	return (mask);
6487c478bd9Sstevel@tonic-gate }
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate /* See if a IP address looks reasonable as a destination */
6527c478bd9Sstevel@tonic-gate boolean_t			/* _B_FALSE=bad _B_TRUE=good */
check_dst(in_addr_t addr)6537c478bd9Sstevel@tonic-gate check_dst(in_addr_t addr)
6547c478bd9Sstevel@tonic-gate {
6557c478bd9Sstevel@tonic-gate 	addr = ntohl(addr);
6567c478bd9Sstevel@tonic-gate 
6577c478bd9Sstevel@tonic-gate 	if (IN_CLASSA(addr)) {
6587c478bd9Sstevel@tonic-gate 		if (addr == 0)
6597c478bd9Sstevel@tonic-gate 			return (_B_TRUE);	/* default */
6607c478bd9Sstevel@tonic-gate 
6617c478bd9Sstevel@tonic-gate 		addr >>= IN_CLASSA_NSHIFT;
6627c478bd9Sstevel@tonic-gate 		return (addr != 0 && addr != IN_LOOPBACKNET);
6637c478bd9Sstevel@tonic-gate 	}
6647c478bd9Sstevel@tonic-gate 
665f9aa3e1eSkcpoon 	/* Must not allow destination to be link local address. */
666f9aa3e1eSkcpoon 	if (IN_LINKLOCAL(addr))
667f9aa3e1eSkcpoon 		return (_B_FALSE);
668f9aa3e1eSkcpoon 
6692a9459bdSsangeeta 	if (IN_CLASSB(addr) || IN_CLASSC(addr))
6702a9459bdSsangeeta 		return (_B_TRUE);
6712a9459bdSsangeeta 
6722a9459bdSsangeeta 	if (IN_CLASSD(addr))
6732a9459bdSsangeeta 		return (_B_FALSE);
6742a9459bdSsangeeta 
6752a9459bdSsangeeta 	return (_B_TRUE);
6762a9459bdSsangeeta 
6777c478bd9Sstevel@tonic-gate }
6787c478bd9Sstevel@tonic-gate 
6797c478bd9Sstevel@tonic-gate /*
6807c478bd9Sstevel@tonic-gate  * Find an existing interface which has the given parameters, but don't
6817c478bd9Sstevel@tonic-gate  * return the interface with name "name" if "name" is specified.
6827c478bd9Sstevel@tonic-gate  */
6837c478bd9Sstevel@tonic-gate struct interface *
check_dup(const char * name,in_addr_t addr,in_addr_t dstaddr,in_addr_t mask,uint64_t if_flags,boolean_t allowdups)6847c478bd9Sstevel@tonic-gate check_dup(const char *name,	/* Don't return this interface */
6857c478bd9Sstevel@tonic-gate     in_addr_t addr,	/* IP address, so network byte order */
6867c478bd9Sstevel@tonic-gate     in_addr_t dstaddr,	/* ditto */
6877c478bd9Sstevel@tonic-gate     in_addr_t mask,	/* mask, so host byte order */
688aee32e3dScarlsonj     uint64_t if_flags,	/* set IFF_POINTOPOINT to ignore local int_addr */
6897c478bd9Sstevel@tonic-gate     boolean_t allowdups)	/* set true to include duplicates */
6907c478bd9Sstevel@tonic-gate {
6917c478bd9Sstevel@tonic-gate 	struct interface *best_ifp = NULL;
6927c478bd9Sstevel@tonic-gate 	struct interface *ifp;
6937c478bd9Sstevel@tonic-gate 	in_addr_t dstaddr_h = ntohl(dstaddr);
6947c478bd9Sstevel@tonic-gate 	int best_pref = 0;
6957c478bd9Sstevel@tonic-gate 	int pref;
6967c478bd9Sstevel@tonic-gate 
6977c478bd9Sstevel@tonic-gate 	for (ifp = ifnet; ifp != NULL; ifp = ifp->int_next) {
6987c478bd9Sstevel@tonic-gate 		/* This interface, not a duplicate. */
6997c478bd9Sstevel@tonic-gate 		if (name != NULL && strcmp(name, ifp->int_name) == 0)
7007c478bd9Sstevel@tonic-gate 			continue;
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate 		/*
7037c478bd9Sstevel@tonic-gate 		 * Find an interface which isn't already a duplicate to
7047c478bd9Sstevel@tonic-gate 		 * avoid cyclical duplication.  (i.e. qfe0:1 is a duplicate
7057c478bd9Sstevel@tonic-gate 		 * of qfe0, and qfe0 is a duplicate of qfe0:1.  That would
7067c478bd9Sstevel@tonic-gate 		 * be bad)
7077c478bd9Sstevel@tonic-gate 		 */
7087c478bd9Sstevel@tonic-gate 		if (!allowdups && (ifp->int_state & IS_DUP))
7097c478bd9Sstevel@tonic-gate 			continue;
7107c478bd9Sstevel@tonic-gate 
7117c478bd9Sstevel@tonic-gate 		if (ifp->int_mask != mask)
7127c478bd9Sstevel@tonic-gate 			continue;
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate 		if (!IS_IFF_UP(ifp->int_if_flags))
7157c478bd9Sstevel@tonic-gate 			continue;
7167c478bd9Sstevel@tonic-gate 
7177c478bd9Sstevel@tonic-gate 		/*
7187c478bd9Sstevel@tonic-gate 		 * The local address can only be shared with a point-to-point
7197c478bd9Sstevel@tonic-gate 		 * link.
7207c478bd9Sstevel@tonic-gate 		 */
7217c478bd9Sstevel@tonic-gate 		if ((ifp->int_addr == addr &&
7227c478bd9Sstevel@tonic-gate 		    ((if_flags|ifp->int_if_flags) & IFF_POINTOPOINT) == 0) ||
7237c478bd9Sstevel@tonic-gate 		    on_net(ifp->int_dstaddr, dstaddr_h, mask)) {
7247c478bd9Sstevel@tonic-gate 			pref = 0;
7257c478bd9Sstevel@tonic-gate 			if (!(ifp->int_state & IS_ALIAS))
7267c478bd9Sstevel@tonic-gate 				pref++;
7277c478bd9Sstevel@tonic-gate 			if (!IS_RIP_OUT_OFF(ifp->int_state))
7287c478bd9Sstevel@tonic-gate 				pref += 2;
7297c478bd9Sstevel@tonic-gate 			if (IS_IFF_ROUTING(ifp->int_if_flags))
7307c478bd9Sstevel@tonic-gate 				pref += 4;
7317c478bd9Sstevel@tonic-gate 			if (pref > best_pref) {
7327c478bd9Sstevel@tonic-gate 				best_pref = pref;
7337c478bd9Sstevel@tonic-gate 				best_ifp = ifp;
7347c478bd9Sstevel@tonic-gate 			}
7357c478bd9Sstevel@tonic-gate 		}
7367c478bd9Sstevel@tonic-gate 	}
7377c478bd9Sstevel@tonic-gate 	return (best_ifp);
7387c478bd9Sstevel@tonic-gate }
7397c478bd9Sstevel@tonic-gate 
7407c478bd9Sstevel@tonic-gate 
7417c478bd9Sstevel@tonic-gate /*
7427c478bd9Sstevel@tonic-gate  * See that a remote gateway is reachable.
7437c478bd9Sstevel@tonic-gate  *	Note that the answer can change as real interfaces come and go.
7447c478bd9Sstevel@tonic-gate  */
7457c478bd9Sstevel@tonic-gate boolean_t			/* _B_FALSE=bad _B_TRUE=good */
check_remote(struct interface * ifp)7467c478bd9Sstevel@tonic-gate check_remote(struct interface *ifp)
7477c478bd9Sstevel@tonic-gate {
7487c478bd9Sstevel@tonic-gate 	struct rt_entry *rt;
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate 	/* do not worry about other kinds */
7517c478bd9Sstevel@tonic-gate 	if (!(ifp->int_state & IS_REMOTE))
7527c478bd9Sstevel@tonic-gate 		return (_B_TRUE);
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate 	rt = rtfind(ifp->int_addr);
7557c478bd9Sstevel@tonic-gate 	if (rt != NULL &&
7567c478bd9Sstevel@tonic-gate 	    rt->rt_ifp != NULL &&
757f9aa3e1eSkcpoon 	    on_net(ifp->int_addr, rt->rt_ifp->int_net, rt->rt_ifp->int_mask)) {
7587c478bd9Sstevel@tonic-gate 		return (_B_TRUE);
759f9aa3e1eSkcpoon 	}
7607c478bd9Sstevel@tonic-gate 
7617c478bd9Sstevel@tonic-gate 	/*
7627c478bd9Sstevel@tonic-gate 	 * the gateway cannot be reached directly from one of our
7637c478bd9Sstevel@tonic-gate 	 * interfaces
7647c478bd9Sstevel@tonic-gate 	 */
7657c478bd9Sstevel@tonic-gate 	if (!(ifp->int_state & IS_BROKE)) {
7667c478bd9Sstevel@tonic-gate 		msglog("unreachable gateway %s in "PATH_GATEWAYS,
7677c478bd9Sstevel@tonic-gate 		    naddr_ntoa(ifp->int_addr));
7687c478bd9Sstevel@tonic-gate 		if_bad(ifp, _B_FALSE);
7697c478bd9Sstevel@tonic-gate 	}
7707c478bd9Sstevel@tonic-gate 	return (_B_FALSE);
7717c478bd9Sstevel@tonic-gate }
7727c478bd9Sstevel@tonic-gate 
7737c478bd9Sstevel@tonic-gate /* Delete an interface. */
7747c478bd9Sstevel@tonic-gate static void
ifdel(struct interface * ifp)7757c478bd9Sstevel@tonic-gate ifdel(struct interface *ifp)
7767c478bd9Sstevel@tonic-gate {
7777c478bd9Sstevel@tonic-gate 	struct rewire_data wire;
7787c478bd9Sstevel@tonic-gate 	boolean_t resurrected;
7797c478bd9Sstevel@tonic-gate 	struct physical_interface *phyi;
7807c478bd9Sstevel@tonic-gate 
7817c478bd9Sstevel@tonic-gate 	trace_if("Del", ifp);
7827c478bd9Sstevel@tonic-gate 
7837c478bd9Sstevel@tonic-gate 	ifp->int_state |= IS_BROKE;
7847c478bd9Sstevel@tonic-gate 
7857c478bd9Sstevel@tonic-gate 	/* unlink the interface */
7867c478bd9Sstevel@tonic-gate 	link_out(ifp, offsetof(struct interface, int_link));
7877c478bd9Sstevel@tonic-gate 	hash_unlink(&ahash_tbl, ifp);
7887c478bd9Sstevel@tonic-gate 	hash_unlink(&nhash_tbl, ifp);
7897c478bd9Sstevel@tonic-gate 	if (ifp->int_if_flags & IFF_BROADCAST)
7907c478bd9Sstevel@tonic-gate 		hash_unlink(&bhash_tbl, ifp);
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate 	/* Remove from list of interfaces with this ifIndex */
7937c478bd9Sstevel@tonic-gate 	if ((phyi = ifp->int_phys) != NULL) {
7947c478bd9Sstevel@tonic-gate 		link_out(ifp, offsetof(struct interface, int_ilist));
7957c478bd9Sstevel@tonic-gate 		if (phyi->phyi_interface == NULL) {
7967c478bd9Sstevel@tonic-gate 			hash_unlink(&ihash_tbl, phyi);
7977c478bd9Sstevel@tonic-gate 			free(phyi);
7987c478bd9Sstevel@tonic-gate 		}
7997c478bd9Sstevel@tonic-gate 	}
8007c478bd9Sstevel@tonic-gate 
8017c478bd9Sstevel@tonic-gate 	/*
8027c478bd9Sstevel@tonic-gate 	 * If this is a lead interface, then check first for
8037c478bd9Sstevel@tonic-gate 	 * duplicates of this interface with an eye towards promoting
8047c478bd9Sstevel@tonic-gate 	 * one of them.
8057c478bd9Sstevel@tonic-gate 	 */
8067c478bd9Sstevel@tonic-gate 	resurrected = _B_FALSE;
8077c478bd9Sstevel@tonic-gate 	if (!(ifp->int_state & IS_DUP) &&
8087c478bd9Sstevel@tonic-gate 	    (wire.if_new = check_dup(ifp->int_name, ifp->int_addr,
8097c478bd9Sstevel@tonic-gate 	    ifp->int_dstaddr, ifp->int_mask, ifp->int_if_flags,
8107c478bd9Sstevel@tonic-gate 	    _B_TRUE)) != NULL &&
8117c478bd9Sstevel@tonic-gate 	    !IS_IFF_QUIET(wire.if_new->int_if_flags)) {
8127c478bd9Sstevel@tonic-gate 
8137c478bd9Sstevel@tonic-gate 		trace_act("promoting duplicate %s in place of %s",
8147c478bd9Sstevel@tonic-gate 		    wire.if_new->int_name, ifp->int_name);
8157c478bd9Sstevel@tonic-gate 
8167c478bd9Sstevel@tonic-gate 		/* Rewire routes with the replacement interface */
8177c478bd9Sstevel@tonic-gate 		wire.if_old = ifp;
8187c478bd9Sstevel@tonic-gate 		wire.metric_delta = wire.if_new->int_metric - ifp->int_metric;
8197c478bd9Sstevel@tonic-gate 		(void) rn_walktree(rhead, walk_rewire, &wire);
8207c478bd9Sstevel@tonic-gate 		kern_rewire_ifp(wire.if_old, wire.if_new);
8217c478bd9Sstevel@tonic-gate 		if_rewire_rdisc(wire.if_old, wire.if_new);
8227c478bd9Sstevel@tonic-gate 
8237c478bd9Sstevel@tonic-gate 		/* Mark the replacement as being no longer a duplicate */
8247c478bd9Sstevel@tonic-gate 		wire.if_new->int_state &= ~IS_DUP;
8257c478bd9Sstevel@tonic-gate 		tot_interfaces++;
8267c478bd9Sstevel@tonic-gate 		if (!IS_RIP_OFF(wire.if_new->int_state))
8277c478bd9Sstevel@tonic-gate 			rip_interfaces++;
8287c478bd9Sstevel@tonic-gate 		if (!IS_RIP_OUT_OFF(wire.if_new->int_state))
8297c478bd9Sstevel@tonic-gate 			ripout_interfaces++;
8307c478bd9Sstevel@tonic-gate 		if (IS_IFF_ROUTING(wire.if_new->int_if_flags))
8317c478bd9Sstevel@tonic-gate 			fwd_interfaces++;
8327c478bd9Sstevel@tonic-gate 
8337c478bd9Sstevel@tonic-gate 		set_rdisc_mg(wire.if_new, 1);
8347c478bd9Sstevel@tonic-gate 		rip_mcast_on(wire.if_new);
8357c478bd9Sstevel@tonic-gate 
8367c478bd9Sstevel@tonic-gate 		/* We came out ok; no need to clobber routes over this. */
8377c478bd9Sstevel@tonic-gate 		resurrected = _B_TRUE;
8387c478bd9Sstevel@tonic-gate 	}
8397c478bd9Sstevel@tonic-gate 
8407c478bd9Sstevel@tonic-gate 	rip_mcast_off(ifp);
8417c478bd9Sstevel@tonic-gate 	if (rip_sock_interface == ifp)
8427c478bd9Sstevel@tonic-gate 		rip_sock_interface = NULL;
8437c478bd9Sstevel@tonic-gate 
8447c478bd9Sstevel@tonic-gate 	set_rdisc_mg(ifp, 0);
8457c478bd9Sstevel@tonic-gate 
8467c478bd9Sstevel@tonic-gate 	/*
8477c478bd9Sstevel@tonic-gate 	 * Note that duplicates are not counted in the total number of
8487c478bd9Sstevel@tonic-gate 	 * interfaces.
8497c478bd9Sstevel@tonic-gate 	 */
8507c478bd9Sstevel@tonic-gate 	if (!(ifp->int_state & IS_DUP) && !IS_IFF_QUIET(ifp->int_if_flags)) {
8517c478bd9Sstevel@tonic-gate 		tot_interfaces--;
8527c478bd9Sstevel@tonic-gate 		if (!IS_RIP_OFF(ifp->int_state))
8537c478bd9Sstevel@tonic-gate 			rip_interfaces--;
8547c478bd9Sstevel@tonic-gate 		if (!IS_RIP_OUT_OFF(ifp->int_state))
8557c478bd9Sstevel@tonic-gate 			ripout_interfaces--;
8567c478bd9Sstevel@tonic-gate 		if (IS_IFF_ROUTING(ifp->int_if_flags))
8577c478bd9Sstevel@tonic-gate 			fwd_interfaces--;
8587c478bd9Sstevel@tonic-gate 	}
8597c478bd9Sstevel@tonic-gate 
8607c478bd9Sstevel@tonic-gate 	if (!resurrected) {
8617c478bd9Sstevel@tonic-gate 		/*
8627c478bd9Sstevel@tonic-gate 		 * Zap all routes associated with this interface.
8637c478bd9Sstevel@tonic-gate 		 * Assume routes just using gateways beyond this interface
8647c478bd9Sstevel@tonic-gate 		 * will timeout naturally, and have probably already died.
8657c478bd9Sstevel@tonic-gate 		 */
8667c478bd9Sstevel@tonic-gate 		(void) rn_walktree(rhead, walk_bad, ifp);
8677c478bd9Sstevel@tonic-gate 		kern_flush_ifp(ifp);
8687c478bd9Sstevel@tonic-gate 
8697c478bd9Sstevel@tonic-gate 		if_bad_rdisc(ifp);
8707c478bd9Sstevel@tonic-gate 	}
8717c478bd9Sstevel@tonic-gate 
8727c478bd9Sstevel@tonic-gate 	free(ifp);
8737c478bd9Sstevel@tonic-gate }
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate 
8767c478bd9Sstevel@tonic-gate /* Mark an interface ill. */
8777c478bd9Sstevel@tonic-gate void
if_sick(struct interface * ifp,boolean_t recurse)8787c478bd9Sstevel@tonic-gate if_sick(struct interface *ifp, boolean_t recurse)
8797c478bd9Sstevel@tonic-gate {
8807c478bd9Sstevel@tonic-gate 	struct interface *ifp1;
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate 	if (0 == (ifp->int_state & (IS_SICK | IS_BROKE))) {
8837c478bd9Sstevel@tonic-gate 		ifp->int_state |= IS_SICK;
8847c478bd9Sstevel@tonic-gate 		ifp->int_act_time = NEVER;
8857c478bd9Sstevel@tonic-gate 		trace_if("Chg", ifp);
8867c478bd9Sstevel@tonic-gate 
8877c478bd9Sstevel@tonic-gate 		LIM_SEC(ifscan_timer, now.tv_sec+CHECK_BAD_INTERVAL);
8887c478bd9Sstevel@tonic-gate 		if (recurse && ifp->int_phys != NULL) {
8897c478bd9Sstevel@tonic-gate 			/* If an interface is sick, so are its aliases. */
8907c478bd9Sstevel@tonic-gate 			for (ifp1 = ifp->int_phys->phyi_interface;
8917c478bd9Sstevel@tonic-gate 			    ifp1 != NULL; ifp1 = ifp1->int_ilist.hl_next) {
8927c478bd9Sstevel@tonic-gate 				if (ifp1 != ifp)
8937c478bd9Sstevel@tonic-gate 					if_sick(ifp1, _B_FALSE);
8947c478bd9Sstevel@tonic-gate 			}
8957c478bd9Sstevel@tonic-gate 		}
8967c478bd9Sstevel@tonic-gate 	}
8977c478bd9Sstevel@tonic-gate }
8987c478bd9Sstevel@tonic-gate 
8997c478bd9Sstevel@tonic-gate 
9007c478bd9Sstevel@tonic-gate /* Mark an interface dead. */
9017c478bd9Sstevel@tonic-gate static void
if_bad(struct interface * ifp,boolean_t recurse)9027c478bd9Sstevel@tonic-gate if_bad(struct interface *ifp, boolean_t recurse)
9037c478bd9Sstevel@tonic-gate {
9047c478bd9Sstevel@tonic-gate 	struct interface *ifp1;
9057c478bd9Sstevel@tonic-gate 	struct rewire_data wire;
9067c478bd9Sstevel@tonic-gate 
9077c478bd9Sstevel@tonic-gate 	if (ifp->int_state & IS_BROKE)
9087c478bd9Sstevel@tonic-gate 		return;
9097c478bd9Sstevel@tonic-gate 
9107c478bd9Sstevel@tonic-gate 	LIM_SEC(ifscan_timer, now.tv_sec+CHECK_BAD_INTERVAL);
9117c478bd9Sstevel@tonic-gate 
9127c478bd9Sstevel@tonic-gate 	ifp->int_state |= (IS_BROKE | IS_SICK);
9137c478bd9Sstevel@tonic-gate 	ifp->int_act_time = NEVER;
9147c478bd9Sstevel@tonic-gate 	ifp->int_query_time = NEVER;
9157c478bd9Sstevel@tonic-gate 	/* Note: don't reset the stats timestamp here */
9167c478bd9Sstevel@tonic-gate 
9177c478bd9Sstevel@tonic-gate 	trace_if("Chg", ifp);
9187c478bd9Sstevel@tonic-gate 
9197c478bd9Sstevel@tonic-gate 	if (recurse && ifp->int_phys != NULL) {
9207c478bd9Sstevel@tonic-gate 		/* If an interface is bad, so are its aliases. */
9217c478bd9Sstevel@tonic-gate 		for (ifp1 = ifp->int_phys->phyi_interface;
9227c478bd9Sstevel@tonic-gate 		    ifp1 != NULL; ifp1 = ifp1->int_ilist.hl_next) {
9237c478bd9Sstevel@tonic-gate 			if (ifp1 != ifp)
9247c478bd9Sstevel@tonic-gate 				if_bad(ifp1, _B_FALSE);
9257c478bd9Sstevel@tonic-gate 		}
9267c478bd9Sstevel@tonic-gate 	}
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate 	/* If we can find a replacement, then pick it up. */
9297c478bd9Sstevel@tonic-gate 	if (!(ifp->int_state & IS_DUP) &&
9307c478bd9Sstevel@tonic-gate 	    (wire.if_new = check_dup(ifp->int_name, ifp->int_addr,
9317c478bd9Sstevel@tonic-gate 	    ifp->int_dstaddr, ifp->int_mask, ifp->int_if_flags,
9327c478bd9Sstevel@tonic-gate 	    _B_TRUE)) != NULL &&
9337c478bd9Sstevel@tonic-gate 	    !IS_IFF_QUIET(wire.if_new->int_if_flags)) {
9347c478bd9Sstevel@tonic-gate 		trace_act("promoting duplicate %s in place of %s",
9357c478bd9Sstevel@tonic-gate 		    wire.if_new->int_name, ifp->int_name);
9367c478bd9Sstevel@tonic-gate 		wire.if_old = ifp;
9377c478bd9Sstevel@tonic-gate 		wire.metric_delta = wire.if_new->int_metric - ifp->int_metric;
9387c478bd9Sstevel@tonic-gate 		(void) rn_walktree(rhead, walk_rewire, &wire);
9397c478bd9Sstevel@tonic-gate 		if_rewire_rdisc(wire.if_old, wire.if_new);
9407c478bd9Sstevel@tonic-gate 
9417c478bd9Sstevel@tonic-gate 		/* The broken guy becomes the duplicate */
9427c478bd9Sstevel@tonic-gate 		wire.if_new->int_state &= ~IS_DUP;
9437c478bd9Sstevel@tonic-gate 		set_rdisc_mg(ifp, 0);
9447c478bd9Sstevel@tonic-gate 		rip_mcast_off(ifp);
9457c478bd9Sstevel@tonic-gate 		ifp->int_state |= IS_DUP;
9467c478bd9Sstevel@tonic-gate 
9477c478bd9Sstevel@tonic-gate 		/* join the mcast groups for the replacement */
9487c478bd9Sstevel@tonic-gate 		set_rdisc_mg(wire.if_new, 1);
9497c478bd9Sstevel@tonic-gate 		rip_mcast_on(wire.if_new);
9507c478bd9Sstevel@tonic-gate 
9517c478bd9Sstevel@tonic-gate 		if (rip_sock_interface == ifp)
9527c478bd9Sstevel@tonic-gate 			rip_sock_interface = NULL;
9537c478bd9Sstevel@tonic-gate 	} else {
9547c478bd9Sstevel@tonic-gate 		(void) rn_walktree(rhead, walk_bad, ifp);
9557c478bd9Sstevel@tonic-gate 		if_bad_rdisc(ifp);
9567c478bd9Sstevel@tonic-gate 	}
9577c478bd9Sstevel@tonic-gate }
9587c478bd9Sstevel@tonic-gate 
9597c478bd9Sstevel@tonic-gate 
9607c478bd9Sstevel@tonic-gate /* Mark an interface alive */
9617c478bd9Sstevel@tonic-gate void
if_ok(struct interface * ifp,const char * type,boolean_t recurse)9627c478bd9Sstevel@tonic-gate if_ok(struct interface *ifp, const char *type, boolean_t recurse)
9637c478bd9Sstevel@tonic-gate {
9647c478bd9Sstevel@tonic-gate 	struct interface *ifp1;
9657c478bd9Sstevel@tonic-gate 	boolean_t wasbroken = _B_FALSE;
9667c478bd9Sstevel@tonic-gate 
9677c478bd9Sstevel@tonic-gate 	if (ifp->int_state & IS_BROKE) {
9687c478bd9Sstevel@tonic-gate 		writelog(LOG_WARNING, "%sinterface %s to %s restored",
9697c478bd9Sstevel@tonic-gate 		    type, ifp->int_name, naddr_ntoa(ifp->int_dstaddr));
9707c478bd9Sstevel@tonic-gate 		ifp->int_state &= ~(IS_BROKE | IS_SICK);
9717c478bd9Sstevel@tonic-gate 		wasbroken = _B_TRUE;
9727c478bd9Sstevel@tonic-gate 	} else if (ifp->int_state & IS_SICK) {
9737c478bd9Sstevel@tonic-gate 		trace_act("%sinterface %s to %s working better",
9747c478bd9Sstevel@tonic-gate 		    type, ifp->int_name, naddr_ntoa(ifp->int_dstaddr));
9757c478bd9Sstevel@tonic-gate 		ifp->int_state &= ~IS_SICK;
9767c478bd9Sstevel@tonic-gate 	}
9777c478bd9Sstevel@tonic-gate 
9787c478bd9Sstevel@tonic-gate 	if (recurse && ifp->int_phys != NULL && IS_IFF_UP(ifp->int_if_flags)) {
9797c478bd9Sstevel@tonic-gate 		ifp->int_phys->phyi_data.ts = 0;
9807c478bd9Sstevel@tonic-gate 
9817c478bd9Sstevel@tonic-gate 		/* Also mark all aliases of this interface as ok */
9827c478bd9Sstevel@tonic-gate 		for (ifp1 = ifp->int_phys->phyi_interface;
9837c478bd9Sstevel@tonic-gate 		    ifp1 != NULL; ifp1 = ifp1->int_ilist.hl_next) {
9847c478bd9Sstevel@tonic-gate 			if (ifp1 != ifp)
9857c478bd9Sstevel@tonic-gate 				if_ok(ifp1, type, _B_FALSE);
9867c478bd9Sstevel@tonic-gate 		}
9877c478bd9Sstevel@tonic-gate 	}
9887c478bd9Sstevel@tonic-gate 
9897c478bd9Sstevel@tonic-gate 	if (wasbroken) {
9907c478bd9Sstevel@tonic-gate 		if (!(ifp->int_state & IS_DUP))
9917c478bd9Sstevel@tonic-gate 			if_ok_rdisc(ifp);
9927c478bd9Sstevel@tonic-gate 
9937c478bd9Sstevel@tonic-gate 		if (ifp->int_state & IS_REMOTE)
9947c478bd9Sstevel@tonic-gate 			(void) addrouteforif(ifp);
9957c478bd9Sstevel@tonic-gate 	}
9967c478bd9Sstevel@tonic-gate }
9977c478bd9Sstevel@tonic-gate 
9987c478bd9Sstevel@tonic-gate boolean_t
remote_address_ok(struct interface * ifp,in_addr_t addr)9997c478bd9Sstevel@tonic-gate remote_address_ok(struct interface *ifp, in_addr_t addr)
10007c478bd9Sstevel@tonic-gate {
10017c478bd9Sstevel@tonic-gate 	if (ifp->int_if_flags & IFF_POINTOPOINT) {
10027c478bd9Sstevel@tonic-gate 		if (addr == ifp->int_dstaddr)
10037c478bd9Sstevel@tonic-gate 			return (_B_TRUE);
10047c478bd9Sstevel@tonic-gate 	} else if (on_net(addr, ifp->int_net, ifp->int_mask)) {
10057c478bd9Sstevel@tonic-gate 		return (_B_TRUE);
10067c478bd9Sstevel@tonic-gate 	}
10077c478bd9Sstevel@tonic-gate 	return (_B_FALSE);
10087c478bd9Sstevel@tonic-gate }
10097c478bd9Sstevel@tonic-gate 
10107c478bd9Sstevel@tonic-gate /*
10117c478bd9Sstevel@tonic-gate  * Find the network interfaces which have configured themselves.
10127c478bd9Sstevel@tonic-gate  *	This must be done regularly, if only for extra addresses
10137c478bd9Sstevel@tonic-gate  *	that come and go on interfaces.
10147c478bd9Sstevel@tonic-gate  */
10157c478bd9Sstevel@tonic-gate void
ifscan(void)10167c478bd9Sstevel@tonic-gate ifscan(void)
10177c478bd9Sstevel@tonic-gate {
10187c478bd9Sstevel@tonic-gate 	uint_t complaints = 0;
10197c478bd9Sstevel@tonic-gate 	static uint_t prev_complaints = 0;
10207c478bd9Sstevel@tonic-gate #define	COMP_BADADDR	0x001
10217c478bd9Sstevel@tonic-gate #define	COMP_NODST	0x002
10227c478bd9Sstevel@tonic-gate #define	COMP_NOBADDR	0x004
10237c478bd9Sstevel@tonic-gate #define	COMP_NOMASK	0x008
10247c478bd9Sstevel@tonic-gate #define	COMP_BAD_METRIC	0x010
10257c478bd9Sstevel@tonic-gate #define	COMP_NETMASK	0x020
10267c478bd9Sstevel@tonic-gate #define	COMP_NO_INDEX	0x040
10277c478bd9Sstevel@tonic-gate #define	COMP_BAD_FLAGS	0x080
10287c478bd9Sstevel@tonic-gate #define	COMP_NO_KSTATS	0x100
10297c478bd9Sstevel@tonic-gate #define	COMP_IPFORWARD	0x200
10307c478bd9Sstevel@tonic-gate 
10317c478bd9Sstevel@tonic-gate 	struct interface ifs, *ifp, *ifp1;
10327c478bd9Sstevel@tonic-gate 	struct rt_entry *rt;
10337c478bd9Sstevel@tonic-gate 	size_t needed;
10347c478bd9Sstevel@tonic-gate 	static size_t lastneeded = 0;
10357c478bd9Sstevel@tonic-gate 	char *buf;
10367c478bd9Sstevel@tonic-gate 	static char *lastbuf = NULL;
10377c478bd9Sstevel@tonic-gate 	int32_t in, ierr, out, oerr;
10387c478bd9Sstevel@tonic-gate 	struct intnet *intnetp;
10397c478bd9Sstevel@tonic-gate 	int sock;
10407c478bd9Sstevel@tonic-gate 	struct lifnum lifn;
10417c478bd9Sstevel@tonic-gate 	struct lifconf lifc;
10427c478bd9Sstevel@tonic-gate 	struct lifreq *lifrp, *lifrp_lim;
10437c478bd9Sstevel@tonic-gate 	struct sockaddr_in *sinp;
10447c478bd9Sstevel@tonic-gate 	in_addr_t haddr;
10457c478bd9Sstevel@tonic-gate 	static in_addr_t myaddr = 0;
10467c478bd9Sstevel@tonic-gate 	uint32_t ifindex;
10477c478bd9Sstevel@tonic-gate 	struct phyi_data newstats;
10487c478bd9Sstevel@tonic-gate 	struct physical_interface *phyi;
10497c478bd9Sstevel@tonic-gate 
10507c478bd9Sstevel@tonic-gate 	last_ifscan = now;
10517c478bd9Sstevel@tonic-gate 	ifscan_timer.tv_sec = now.tv_sec +
10527c478bd9Sstevel@tonic-gate 	    (supplier || tot_interfaces != 1 ?
10537c478bd9Sstevel@tonic-gate 	    CHECK_ACT_INTERVAL : CHECK_QUIET_INTERVAL);
10547c478bd9Sstevel@tonic-gate 
10557c478bd9Sstevel@tonic-gate 	/* mark all interfaces so we can get rid of those that disappear */
10567c478bd9Sstevel@tonic-gate 	for (ifp = ifnet; ifp != NULL; ifp = ifp->int_next)
10577c478bd9Sstevel@tonic-gate 		ifp->int_state &= ~IS_CHECKED;
10587c478bd9Sstevel@tonic-gate 
10597c478bd9Sstevel@tonic-gate 	/* Fetch the size of the current interface list */
10607c478bd9Sstevel@tonic-gate 	if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
10617c478bd9Sstevel@tonic-gate 		BADERR(_B_TRUE, "ifscan: socket(SOCK_DGRAM)");
10627c478bd9Sstevel@tonic-gate 	lifn.lifn_family = AF_INET;	/* Only count IPv4 interfaces */
10637c478bd9Sstevel@tonic-gate 	/*
10647c478bd9Sstevel@tonic-gate 	 * Include IFF_NOXMIT interfaces.  Such interfaces are exluded
10657c478bd9Sstevel@tonic-gate 	 * from protocol operations, but their inclusion in the
10667c478bd9Sstevel@tonic-gate 	 * internal table enables us to know when packets arrive on
10677c478bd9Sstevel@tonic-gate 	 * such interfaces.
10687c478bd9Sstevel@tonic-gate 	 */
10697c478bd9Sstevel@tonic-gate 	lifn.lifn_flags = LIFC_NOXMIT;
10707c478bd9Sstevel@tonic-gate calculate_lifc_len:
10717c478bd9Sstevel@tonic-gate 	if (ioctl(sock, SIOCGLIFNUM, &lifn) == -1) {
10727c478bd9Sstevel@tonic-gate 		BADERR(_B_TRUE, "ifscan: ioctl(SIOCGLIFNUM)");
10737c478bd9Sstevel@tonic-gate 	}
10747c478bd9Sstevel@tonic-gate 
10757c478bd9Sstevel@tonic-gate 	/*
10767c478bd9Sstevel@tonic-gate 	 * When calculating the buffer size needed, add a small number
10777c478bd9Sstevel@tonic-gate 	 * of interfaces to those we counted.  We do this to capture
10787c478bd9Sstevel@tonic-gate 	 * the interface status of potential interfaces which may have
10797c478bd9Sstevel@tonic-gate 	 * been plumbed between the SIOCGLIFNUM and the SIOCGLIFCONF.
10807c478bd9Sstevel@tonic-gate 	 * Try to reuse the buffer we already have to avoid heap
10817c478bd9Sstevel@tonic-gate 	 * thrash.
10827c478bd9Sstevel@tonic-gate 	 */
10837c478bd9Sstevel@tonic-gate 	needed = (lifn.lifn_count + 4) * sizeof (struct lifreq);
10847c478bd9Sstevel@tonic-gate 	if (needed > lastneeded || needed < lastneeded/2) {
10857c478bd9Sstevel@tonic-gate 		if (lastbuf != NULL)
10867c478bd9Sstevel@tonic-gate 			free(lastbuf);
10877c478bd9Sstevel@tonic-gate 		if ((buf = malloc(needed)) == NULL) {
10887c478bd9Sstevel@tonic-gate 			lastbuf = NULL;
10897c478bd9Sstevel@tonic-gate 			msglog("ifscan: malloc: %s", rip_strerror(errno));
10907c478bd9Sstevel@tonic-gate 			return;
10917c478bd9Sstevel@tonic-gate 		}
10927c478bd9Sstevel@tonic-gate 	} else {
10937c478bd9Sstevel@tonic-gate 		buf = lastbuf;
10947c478bd9Sstevel@tonic-gate 	}
10957c478bd9Sstevel@tonic-gate 	lastbuf = buf;
10967c478bd9Sstevel@tonic-gate 	lastneeded = needed;
10977c478bd9Sstevel@tonic-gate 
10987c478bd9Sstevel@tonic-gate 	/* Get the list */
10997c478bd9Sstevel@tonic-gate 	lifc.lifc_family = AF_INET;	/* We only need IPv4 interfaces */
11007c478bd9Sstevel@tonic-gate 	lifc.lifc_flags = LIFC_NOXMIT;
11017c478bd9Sstevel@tonic-gate 	lifc.lifc_len = needed;
11027c478bd9Sstevel@tonic-gate 	lifc.lifc_buf = buf;
11037c478bd9Sstevel@tonic-gate 	if (ioctl(sock, SIOCGLIFCONF, &lifc) == -1) {
11047c478bd9Sstevel@tonic-gate 		/*
11057c478bd9Sstevel@tonic-gate 		 * IP returns EINVAL if the lifc_len we passed in is
11067c478bd9Sstevel@tonic-gate 		 * too small.  If that's the case, we need to go back
11077c478bd9Sstevel@tonic-gate 		 * and recalculate it.
11087c478bd9Sstevel@tonic-gate 		 */
11097c478bd9Sstevel@tonic-gate 		if (errno == EINVAL)
11107c478bd9Sstevel@tonic-gate 			goto calculate_lifc_len;
11117c478bd9Sstevel@tonic-gate 		BADERR(_B_TRUE, "ifscan: ioctl(SIOCGLIFCONF)");
11127c478bd9Sstevel@tonic-gate 	}
11137c478bd9Sstevel@tonic-gate 
11147c478bd9Sstevel@tonic-gate 	/*
11157c478bd9Sstevel@tonic-gate 	 * If the returned lifc_len is within one lifreq of the
11167c478bd9Sstevel@tonic-gate 	 * requested ammount, we may have used a buffer which
11177c478bd9Sstevel@tonic-gate 	 * was too small to hold all of the interfaces.  In that
11187c478bd9Sstevel@tonic-gate 	 * case go back and recalculate needed.
11197c478bd9Sstevel@tonic-gate 	 */
11207c478bd9Sstevel@tonic-gate 	if (lifc.lifc_len >= needed - sizeof (struct lifreq))
11217c478bd9Sstevel@tonic-gate 		goto calculate_lifc_len;
11227c478bd9Sstevel@tonic-gate 
11237c478bd9Sstevel@tonic-gate 	lifrp = lifc.lifc_req;
11247c478bd9Sstevel@tonic-gate 	lifrp_lim = lifrp + lifc.lifc_len / sizeof (*lifrp);
11257c478bd9Sstevel@tonic-gate 	for (; lifrp < lifrp_lim; lifrp++) {
11267c478bd9Sstevel@tonic-gate 
11277c478bd9Sstevel@tonic-gate 		(void) memset(&ifs, 0, sizeof (ifs));
11287c478bd9Sstevel@tonic-gate 
11297c478bd9Sstevel@tonic-gate 		(void) strlcpy(ifs.int_name, lifrp->lifr_name,
11307c478bd9Sstevel@tonic-gate 		    sizeof (ifs.int_name));
11317c478bd9Sstevel@tonic-gate 
11327c478bd9Sstevel@tonic-gate 		/* SIOCGLIFCONF fills in the lifr_addr of each lifreq */
11337c478bd9Sstevel@tonic-gate 		ifs.int_addr = ((struct sockaddr_in *)&lifrp->lifr_addr)->
11347c478bd9Sstevel@tonic-gate 		    sin_addr.s_addr;
11357c478bd9Sstevel@tonic-gate 
11367c478bd9Sstevel@tonic-gate 		if (ioctl(sock, SIOCGLIFFLAGS, lifrp) == -1) {
11377c478bd9Sstevel@tonic-gate 			if (!(prev_complaints & COMP_BAD_FLAGS))
11387c478bd9Sstevel@tonic-gate 				writelog(LOG_NOTICE,
11397c478bd9Sstevel@tonic-gate 				    "unable to get interface flags for %s: %s",
11407c478bd9Sstevel@tonic-gate 				    ifs.int_name, rip_strerror(errno));
11417c478bd9Sstevel@tonic-gate 			complaints |= COMP_BAD_FLAGS;
11427c478bd9Sstevel@tonic-gate 			ifs.int_if_flags = 0;
11437c478bd9Sstevel@tonic-gate 		} else {
11447c478bd9Sstevel@tonic-gate 			ifs.int_if_flags = lifrp->lifr_flags;
11457c478bd9Sstevel@tonic-gate 		}
11467c478bd9Sstevel@tonic-gate 
11472a9459bdSsangeeta 		if (IN_CLASSD(ntohl(ifs.int_addr)) ||
11487c478bd9Sstevel@tonic-gate 		    (ntohl(ifs.int_addr) & IN_CLASSA_NET) == 0) {
11497c478bd9Sstevel@tonic-gate 			if (IS_IFF_UP(ifs.int_if_flags)) {
11507c478bd9Sstevel@tonic-gate 				if (!(prev_complaints & COMP_BADADDR))
11517c478bd9Sstevel@tonic-gate 					writelog(LOG_NOTICE,
11527c478bd9Sstevel@tonic-gate 					    "%s has a bad address %s",
11537c478bd9Sstevel@tonic-gate 					    ifs.int_name,
11547c478bd9Sstevel@tonic-gate 					    naddr_ntoa(ifs.int_addr));
11557c478bd9Sstevel@tonic-gate 				complaints |= COMP_BADADDR;
11567c478bd9Sstevel@tonic-gate 			}
11577c478bd9Sstevel@tonic-gate 			continue;
11587c478bd9Sstevel@tonic-gate 		}
11597c478bd9Sstevel@tonic-gate 
1160f9aa3e1eSkcpoon 		/* Ignore interface with IPv4 link local address. */
1161f9aa3e1eSkcpoon 		if (IN_LINKLOCAL(ntohl(ifs.int_addr)))
1162f9aa3e1eSkcpoon 			continue;
1163f9aa3e1eSkcpoon 
11647c478bd9Sstevel@tonic-gate 		/* Get the interface index. */
11657c478bd9Sstevel@tonic-gate 		if (ioctl(sock, SIOCGLIFINDEX, lifrp) == -1) {
11667c478bd9Sstevel@tonic-gate 			ifindex = 0;
11677c478bd9Sstevel@tonic-gate 			ifs.int_if_flags &= ~IFF_UP;
11687c478bd9Sstevel@tonic-gate 			if (!(prev_complaints & COMP_NO_INDEX))
11697c478bd9Sstevel@tonic-gate 				writelog(LOG_NOTICE, "%s has no ifIndex: %s",
11707c478bd9Sstevel@tonic-gate 				    ifs.int_name, rip_strerror(errno));
11717c478bd9Sstevel@tonic-gate 			complaints |= COMP_NO_INDEX;
11727c478bd9Sstevel@tonic-gate 		} else {
11737c478bd9Sstevel@tonic-gate 			ifindex = lifrp->lifr_index;
11747c478bd9Sstevel@tonic-gate 		}
11757c478bd9Sstevel@tonic-gate 
11767c478bd9Sstevel@tonic-gate 		/*
11777c478bd9Sstevel@tonic-gate 		 * Get the destination address for point-to-point
11787c478bd9Sstevel@tonic-gate 		 * interfaces.
11797c478bd9Sstevel@tonic-gate 		 */
11807c478bd9Sstevel@tonic-gate 		if (ifs.int_if_flags & IFF_POINTOPOINT) {
11817c478bd9Sstevel@tonic-gate 			sinp = (struct sockaddr_in *)&lifrp->lifr_dstaddr;
11827c478bd9Sstevel@tonic-gate 			if (ioctl(sock, SIOCGLIFDSTADDR, lifrp) == -1) {
11837c478bd9Sstevel@tonic-gate 				if (IS_IFF_UP(ifs.int_if_flags)) {
11847c478bd9Sstevel@tonic-gate 					if (!(prev_complaints & COMP_NODST))
11857c478bd9Sstevel@tonic-gate 						writelog(LOG_NOTICE,
11867c478bd9Sstevel@tonic-gate 						    "%s has no destination "
11877c478bd9Sstevel@tonic-gate 						    "address : %s",
11887c478bd9Sstevel@tonic-gate 						    ifs.int_name,
11897c478bd9Sstevel@tonic-gate 						    rip_strerror(errno));
11907c478bd9Sstevel@tonic-gate 					complaints |= COMP_NODST;
11917c478bd9Sstevel@tonic-gate 				}
11927c478bd9Sstevel@tonic-gate 				continue;
11937c478bd9Sstevel@tonic-gate 			}
11947c478bd9Sstevel@tonic-gate 			ifs.int_net = ntohl(sinp->sin_addr.s_addr);
11952a9459bdSsangeeta 			if (IN_CLASSD(ntohl(ifs.int_net)) ||
11967c478bd9Sstevel@tonic-gate 			    (ifs.int_net != 0 &&
11977c478bd9Sstevel@tonic-gate 			    (ifs.int_net & IN_CLASSA_NET) == 0)) {
11987c478bd9Sstevel@tonic-gate 				if (IS_IFF_UP(ifs.int_if_flags)) {
11997c478bd9Sstevel@tonic-gate 					if (!(prev_complaints & COMP_NODST))
12007c478bd9Sstevel@tonic-gate 						writelog(LOG_NOTICE,
12017c478bd9Sstevel@tonic-gate 						    "%s has a bad "
12027c478bd9Sstevel@tonic-gate 						    "destination address %s",
12037c478bd9Sstevel@tonic-gate 						    ifs.int_name,
12047c478bd9Sstevel@tonic-gate 						    naddr_ntoa(ifs.int_net));
12057c478bd9Sstevel@tonic-gate 					complaints |= COMP_NODST;
12067c478bd9Sstevel@tonic-gate 				}
12077c478bd9Sstevel@tonic-gate 				continue;
12087c478bd9Sstevel@tonic-gate 			}
12097c478bd9Sstevel@tonic-gate 			ifs.int_dstaddr = sinp->sin_addr.s_addr;
12107c478bd9Sstevel@tonic-gate 		}
12117c478bd9Sstevel@tonic-gate 
12127c478bd9Sstevel@tonic-gate 		/* Get the subnet mask */
12137c478bd9Sstevel@tonic-gate 		sinp = (struct sockaddr_in *)&lifrp->lifr_addr;
12147c478bd9Sstevel@tonic-gate 		if (ioctl(sock, SIOCGLIFNETMASK, lifrp) == -1) {
12157c478bd9Sstevel@tonic-gate 			if (IS_IFF_UP(ifs.int_if_flags)) {
12167c478bd9Sstevel@tonic-gate 				if (!(prev_complaints & COMP_NOMASK))
12177c478bd9Sstevel@tonic-gate 					writelog(LOG_NOTICE,
12187c478bd9Sstevel@tonic-gate 					    "%s has no netmask: %s",
12197c478bd9Sstevel@tonic-gate 					    ifs.int_name, rip_strerror(errno));
12207c478bd9Sstevel@tonic-gate 				complaints |= COMP_NOMASK;
12217c478bd9Sstevel@tonic-gate 			}
12227c478bd9Sstevel@tonic-gate 			continue;
12237c478bd9Sstevel@tonic-gate 		}
12247c478bd9Sstevel@tonic-gate 		if (sinp->sin_addr.s_addr == INADDR_ANY) {
12257c478bd9Sstevel@tonic-gate 			if (!(ifs.int_if_flags &
12267c478bd9Sstevel@tonic-gate 			    (IFF_POINTOPOINT|IFF_LOOPBACK))) {
12277c478bd9Sstevel@tonic-gate 				if (IS_IFF_UP(ifs.int_if_flags)) {
12287c478bd9Sstevel@tonic-gate 					if (!(prev_complaints & COMP_NOMASK))
12297c478bd9Sstevel@tonic-gate 						writelog(LOG_NOTICE,
12307c478bd9Sstevel@tonic-gate 						    "%s has all-zero netmask",
12317c478bd9Sstevel@tonic-gate 						    ifs.int_name);
12327c478bd9Sstevel@tonic-gate 					complaints |= COMP_NOMASK;
12337c478bd9Sstevel@tonic-gate 				}
12347c478bd9Sstevel@tonic-gate 				continue;
12357c478bd9Sstevel@tonic-gate 			}
12367c478bd9Sstevel@tonic-gate 			ifs.int_mask = IP_HOST_MASK;
12377c478bd9Sstevel@tonic-gate 		} else {
12387c478bd9Sstevel@tonic-gate 			ifs.int_mask = ntohl(sinp->sin_addr.s_addr);
12397c478bd9Sstevel@tonic-gate 		}
12407c478bd9Sstevel@tonic-gate 
12417c478bd9Sstevel@tonic-gate 		/*
12427c478bd9Sstevel@tonic-gate 		 * Get the broadcast address on broadcast capable
12437c478bd9Sstevel@tonic-gate 		 * interfaces.
12447c478bd9Sstevel@tonic-gate 		 */
12457c478bd9Sstevel@tonic-gate 		if (ifs.int_if_flags & IFF_BROADCAST) {
12467c478bd9Sstevel@tonic-gate 			if (ioctl(sock, SIOCGLIFBRDADDR, lifrp) == -1) {
12477c478bd9Sstevel@tonic-gate 				if (IS_IFF_UP(ifs.int_if_flags)) {
12487c478bd9Sstevel@tonic-gate 					if (!(prev_complaints & COMP_NOBADDR))
12497c478bd9Sstevel@tonic-gate 						writelog(LOG_NOTICE,
12507c478bd9Sstevel@tonic-gate 						    "%s has no broadcast "
12517c478bd9Sstevel@tonic-gate 						    "address: %s",
12527c478bd9Sstevel@tonic-gate 						    ifs.int_name,
12537c478bd9Sstevel@tonic-gate 						    rip_strerror(errno));
12547c478bd9Sstevel@tonic-gate 					complaints |= COMP_NOBADDR;
12557c478bd9Sstevel@tonic-gate 				}
12567c478bd9Sstevel@tonic-gate 				continue;
12577c478bd9Sstevel@tonic-gate 			}
12587c478bd9Sstevel@tonic-gate 			haddr = ntohl(sinp->sin_addr.s_addr);
12592a9459bdSsangeeta 			if (IN_CLASSD(haddr) ||
12607c478bd9Sstevel@tonic-gate 			    (haddr & IN_CLASSA_NET) == 0) {
12617c478bd9Sstevel@tonic-gate 				if (IS_IFF_UP(ifs.int_if_flags)) {
12627c478bd9Sstevel@tonic-gate 					if (!(prev_complaints & COMP_NOBADDR))
12637c478bd9Sstevel@tonic-gate 						writelog(LOG_NOTICE,
12647c478bd9Sstevel@tonic-gate 						    "%s has a bad broadcast "
12657c478bd9Sstevel@tonic-gate 						    "address %s",
12667c478bd9Sstevel@tonic-gate 						    ifs.int_name,
12677c478bd9Sstevel@tonic-gate 						    naddr_ntoa(haddr));
12687c478bd9Sstevel@tonic-gate 					complaints |= COMP_NOBADDR;
12697c478bd9Sstevel@tonic-gate 				}
12707c478bd9Sstevel@tonic-gate 				continue;
12717c478bd9Sstevel@tonic-gate 			}
12727c478bd9Sstevel@tonic-gate 		}
12737c478bd9Sstevel@tonic-gate 		ifs.int_brdaddr = sinp->sin_addr.s_addr;
12747c478bd9Sstevel@tonic-gate 
12757c478bd9Sstevel@tonic-gate 		/* Get interface metric, if possible. */
12767c478bd9Sstevel@tonic-gate 		if (ioctl(sock, SIOCGLIFMETRIC, lifrp) == -1) {
12777c478bd9Sstevel@tonic-gate 			if (IS_IFF_UP(ifs.int_if_flags)) {
12787c478bd9Sstevel@tonic-gate 				if (!(prev_complaints & COMP_BAD_METRIC))
12797c478bd9Sstevel@tonic-gate 					writelog(LOG_NOTICE,
12807c478bd9Sstevel@tonic-gate 					    "%s has no metric: %s",
12817c478bd9Sstevel@tonic-gate 					    ifs.int_name, rip_strerror(errno));
12827c478bd9Sstevel@tonic-gate 				complaints |= COMP_BAD_METRIC;
12837c478bd9Sstevel@tonic-gate 			}
12847c478bd9Sstevel@tonic-gate 		} else {
12857c478bd9Sstevel@tonic-gate 			ifs.int_metric = lifrp->lifr_metric;
12867c478bd9Sstevel@tonic-gate 			if (ifs.int_metric > HOPCNT_INFINITY) {
12877c478bd9Sstevel@tonic-gate 				if (IS_IFF_UP(ifs.int_if_flags)) {
12887c478bd9Sstevel@tonic-gate 					if (!(prev_complaints &
12897c478bd9Sstevel@tonic-gate 					    COMP_BAD_METRIC))
12907c478bd9Sstevel@tonic-gate 						writelog(LOG_NOTICE,
12917c478bd9Sstevel@tonic-gate 						    "%s has a metric of %d, "
12927c478bd9Sstevel@tonic-gate 						    "defaulting to %d",
12937c478bd9Sstevel@tonic-gate 						    ifs.int_name,
12947c478bd9Sstevel@tonic-gate 						    ifs.int_metric,
12957c478bd9Sstevel@tonic-gate 						    HOPCNT_INFINITY);
12967c478bd9Sstevel@tonic-gate 					complaints |= COMP_BAD_METRIC;
12977c478bd9Sstevel@tonic-gate 				}
12987c478bd9Sstevel@tonic-gate 				ifs.int_metric = HOPCNT_INFINITY;
12997c478bd9Sstevel@tonic-gate 			}
13007c478bd9Sstevel@tonic-gate 		}
13017c478bd9Sstevel@tonic-gate 
13027c478bd9Sstevel@tonic-gate 		ifs.int_state |= IS_CHECKED;
13037c478bd9Sstevel@tonic-gate 		ifs.int_query_time = NEVER;
13047c478bd9Sstevel@tonic-gate 
13057c478bd9Sstevel@tonic-gate 		/*
13067c478bd9Sstevel@tonic-gate 		 * If this is an alias, then mark it appropriately.
13077c478bd9Sstevel@tonic-gate 		 * Do not output RIP or Router-Discovery packets via
13087c478bd9Sstevel@tonic-gate 		 * aliases.
13097c478bd9Sstevel@tonic-gate 		 */
13107c478bd9Sstevel@tonic-gate 		if (strchr(ifs.int_name, ':') != NULL)
13117c478bd9Sstevel@tonic-gate 			ifs.int_state |= IS_ALIAS;
13127c478bd9Sstevel@tonic-gate 
13137c478bd9Sstevel@tonic-gate 		if (ifs.int_if_flags & IFF_LOOPBACK) {
13147c478bd9Sstevel@tonic-gate 			ifs.int_state |= IS_PASSIVE | IS_NO_RIP | IS_NO_RDISC;
13157c478bd9Sstevel@tonic-gate 			ifs.int_dstaddr = ifs.int_addr;
13167c478bd9Sstevel@tonic-gate 			ifs.int_mask = HOST_MASK;
13177c478bd9Sstevel@tonic-gate 			ifs.int_ripv1_mask = HOST_MASK;
13187c478bd9Sstevel@tonic-gate 			ifs.int_std_mask = std_mask(ifs.int_dstaddr);
13197c478bd9Sstevel@tonic-gate 			ifs.int_net = ntohl(ifs.int_dstaddr);
13207c478bd9Sstevel@tonic-gate 			if (!foundloopback) {
13217c478bd9Sstevel@tonic-gate 				foundloopback = _B_TRUE;
13227c478bd9Sstevel@tonic-gate 				loopaddr = ifs.int_addr;
13237c478bd9Sstevel@tonic-gate 				loop_rts.rts_gate = loopaddr;
13247c478bd9Sstevel@tonic-gate 				loop_rts.rts_router = loopaddr;
13257c478bd9Sstevel@tonic-gate 			}
13267c478bd9Sstevel@tonic-gate 
13277c478bd9Sstevel@tonic-gate 		} else if (ifs.int_if_flags & IFF_POINTOPOINT) {
13287c478bd9Sstevel@tonic-gate 			ifs.int_ripv1_mask = ifs.int_mask;
13297c478bd9Sstevel@tonic-gate 			ifs.int_mask = HOST_MASK;
13307c478bd9Sstevel@tonic-gate 			ifs.int_std_mask = std_mask(ifs.int_dstaddr);
13317c478bd9Sstevel@tonic-gate 
13327c478bd9Sstevel@tonic-gate 		} else {
13337c478bd9Sstevel@tonic-gate 			ifs.int_dstaddr = ifs.int_addr;
13347c478bd9Sstevel@tonic-gate 			ifs.int_ripv1_mask = ifs.int_mask;
13357c478bd9Sstevel@tonic-gate 			ifs.int_std_mask = std_mask(ifs.int_addr);
13367c478bd9Sstevel@tonic-gate 			ifs.int_net = ntohl(ifs.int_addr) & ifs.int_mask;
13377c478bd9Sstevel@tonic-gate 			if (ifs.int_mask != ifs.int_std_mask)
13387c478bd9Sstevel@tonic-gate 				ifs.int_state |= IS_SUBNET;
13397c478bd9Sstevel@tonic-gate 		}
13407c478bd9Sstevel@tonic-gate 		ifs.int_std_net = ifs.int_net & ifs.int_std_mask;
13417c478bd9Sstevel@tonic-gate 		ifs.int_std_addr = htonl(ifs.int_std_net);
13427c478bd9Sstevel@tonic-gate 
13437c478bd9Sstevel@tonic-gate 		/*
13447c478bd9Sstevel@tonic-gate 		 * If this interface duplicates another, mark it
13457c478bd9Sstevel@tonic-gate 		 * appropriately so that we don't generate duplicate
13467c478bd9Sstevel@tonic-gate 		 * packets.
13477c478bd9Sstevel@tonic-gate 		 */
13487c478bd9Sstevel@tonic-gate 		ifp = check_dup(ifs.int_name, ifs.int_addr, ifs.int_dstaddr,
13497c478bd9Sstevel@tonic-gate 		    ifs.int_mask, ifs.int_if_flags, _B_FALSE);
13507c478bd9Sstevel@tonic-gate 		if (ifp != NULL) {
13517c478bd9Sstevel@tonic-gate 			trace_misc("%s (%s%s%s) is a duplicate of %s (%s%s%s)",
13527c478bd9Sstevel@tonic-gate 			    ifs.int_name,
13537c478bd9Sstevel@tonic-gate 			    addrname(ifs.int_addr, ifs.int_mask, 1),
13547c478bd9Sstevel@tonic-gate 			    ((ifs.int_if_flags & IFF_POINTOPOINT) ?
13557c478bd9Sstevel@tonic-gate 			    "-->" : ""),
13567c478bd9Sstevel@tonic-gate 			    ((ifs.int_if_flags & IFF_POINTOPOINT) ?
13577c478bd9Sstevel@tonic-gate 			    naddr_ntoa(ifs.int_dstaddr) : ""),
13587c478bd9Sstevel@tonic-gate 			    ifp->int_name,
13597c478bd9Sstevel@tonic-gate 			    addrname(ifp->int_addr, ifp->int_mask, 1),
13607c478bd9Sstevel@tonic-gate 			    ((ifp->int_if_flags & IFF_POINTOPOINT) ?
13617c478bd9Sstevel@tonic-gate 			    "-->" : ""),
13627c478bd9Sstevel@tonic-gate 			    ((ifp->int_if_flags & IFF_POINTOPOINT) ?
13637c478bd9Sstevel@tonic-gate 			    naddr_ntoa(ifp->int_dstaddr) : ""));
13647c478bd9Sstevel@tonic-gate 			ifs.int_state |= IS_DUP;
13657c478bd9Sstevel@tonic-gate 		} else {
13667c478bd9Sstevel@tonic-gate 			ifs.int_state &= ~IS_DUP;
13677c478bd9Sstevel@tonic-gate 		}
13687c478bd9Sstevel@tonic-gate 
13697c478bd9Sstevel@tonic-gate 		/*
13707c478bd9Sstevel@tonic-gate 		 * See if this is a familiar interface.
13717c478bd9Sstevel@tonic-gate 		 * If so, stop worrying about it if it is the same.
13727c478bd9Sstevel@tonic-gate 		 * Start it over if it now is to somewhere else, as happens
13737c478bd9Sstevel@tonic-gate 		 * frequently with PPP and SLIP, or if its forwarding
13747c478bd9Sstevel@tonic-gate 		 * status has changed.
13757c478bd9Sstevel@tonic-gate 		 */
13767c478bd9Sstevel@tonic-gate 		ifp = ifwithname(ifs.int_name);
13777c478bd9Sstevel@tonic-gate 		if (ifp != NULL) {
13787c478bd9Sstevel@tonic-gate 			ifp->int_state |= IS_CHECKED;
13797c478bd9Sstevel@tonic-gate 			ifp->int_state = (ifp->int_state & ~IS_DUP) |
13807c478bd9Sstevel@tonic-gate 			    (ifs.int_state & IS_DUP);
13817c478bd9Sstevel@tonic-gate 
13827c478bd9Sstevel@tonic-gate 			if ((ifp->int_phys == NULL && ifindex != 0) ||
13837c478bd9Sstevel@tonic-gate 			    (ifp->int_phys != NULL &&
13847c478bd9Sstevel@tonic-gate 			    ifp->int_phys->phyi_index != ifindex) ||
13857c478bd9Sstevel@tonic-gate 			    0 != ((ifp->int_if_flags ^ ifs.int_if_flags)
13867c478bd9Sstevel@tonic-gate 			    & (IFF_BROADCAST | IFF_LOOPBACK |
13877c478bd9Sstevel@tonic-gate 			    IFF_POINTOPOINT | IFF_MULTICAST |
13887c478bd9Sstevel@tonic-gate 			    IFF_ROUTER | IFF_NORTEXCH | IFF_NOXMIT)) ||
13897c478bd9Sstevel@tonic-gate 			    ifp->int_addr != ifs.int_addr ||
13907c478bd9Sstevel@tonic-gate 			    ifp->int_brdaddr != ifs.int_brdaddr ||
13917c478bd9Sstevel@tonic-gate 			    ifp->int_dstaddr != ifs.int_dstaddr ||
13927c478bd9Sstevel@tonic-gate 			    ifp->int_mask != ifs.int_mask ||
13937c478bd9Sstevel@tonic-gate 			    ifp->int_metric != ifs.int_metric) {
13947c478bd9Sstevel@tonic-gate 				/*
13957c478bd9Sstevel@tonic-gate 				 * Forget old information about
13967c478bd9Sstevel@tonic-gate 				 * a changed interface.
13977c478bd9Sstevel@tonic-gate 				 */
13987c478bd9Sstevel@tonic-gate 				trace_act("interface %s has changed",
13997c478bd9Sstevel@tonic-gate 				    ifp->int_name);
14007c478bd9Sstevel@tonic-gate 				ifdel(ifp);
14017c478bd9Sstevel@tonic-gate 				ifp = NULL;
14027c478bd9Sstevel@tonic-gate 			}
14037c478bd9Sstevel@tonic-gate 		}
14047c478bd9Sstevel@tonic-gate 
14057c478bd9Sstevel@tonic-gate 		if (ifp != NULL) {
14067c478bd9Sstevel@tonic-gate 			/* note interfaces that have been turned off */
14077c478bd9Sstevel@tonic-gate 			if (!IS_IFF_UP(ifs.int_if_flags)) {
14087c478bd9Sstevel@tonic-gate 				if (IS_IFF_UP(ifp->int_if_flags)) {
14097c478bd9Sstevel@tonic-gate 					writelog(LOG_WARNING,
14107c478bd9Sstevel@tonic-gate 					    "interface %s to %s turned off",
14117c478bd9Sstevel@tonic-gate 					    ifp->int_name,
14127c478bd9Sstevel@tonic-gate 					    naddr_ntoa(ifp->int_dstaddr));
14137c478bd9Sstevel@tonic-gate 					if_bad(ifp, _B_FALSE);
14147c478bd9Sstevel@tonic-gate 					ifp->int_if_flags &= ~IFF_UP;
14157c478bd9Sstevel@tonic-gate 				} else if (ifp->int_phys != NULL &&
14167c478bd9Sstevel@tonic-gate 				    now.tv_sec > (ifp->int_phys->phyi_data.ts +
14177c478bd9Sstevel@tonic-gate 				    CHECK_BAD_INTERVAL)) {
14187c478bd9Sstevel@tonic-gate 					trace_act("interface %s has been off"
14197c478bd9Sstevel@tonic-gate 					    " %ld seconds; forget it",
14207c478bd9Sstevel@tonic-gate 					    ifp->int_name,
14217c478bd9Sstevel@tonic-gate 					    now.tv_sec -
14227c478bd9Sstevel@tonic-gate 					    ifp->int_phys->phyi_data.ts);
14237c478bd9Sstevel@tonic-gate 					ifdel(ifp);
14247c478bd9Sstevel@tonic-gate 				}
14257c478bd9Sstevel@tonic-gate 				continue;
14267c478bd9Sstevel@tonic-gate 			}
14277c478bd9Sstevel@tonic-gate 			/* or that were off and are now ok */
14287c478bd9Sstevel@tonic-gate 			if (!IS_IFF_UP(ifp->int_if_flags)) {
14297c478bd9Sstevel@tonic-gate 				ifp->int_if_flags |= IFF_UP;
14307c478bd9Sstevel@tonic-gate 				if_ok(ifp, "", _B_FALSE);
14317c478bd9Sstevel@tonic-gate 			}
14327c478bd9Sstevel@tonic-gate 
14337c478bd9Sstevel@tonic-gate 			/*
14347c478bd9Sstevel@tonic-gate 			 * If it has been long enough,
14357c478bd9Sstevel@tonic-gate 			 * see if the interface is broken.
14367c478bd9Sstevel@tonic-gate 			 */
14377c478bd9Sstevel@tonic-gate 			if ((phyi = ifp->int_phys) == NULL ||
14387c478bd9Sstevel@tonic-gate 			    now.tv_sec < phyi->phyi_data.ts +
14397c478bd9Sstevel@tonic-gate 			    CHECK_BAD_INTERVAL)
14407c478bd9Sstevel@tonic-gate 				continue;
14417c478bd9Sstevel@tonic-gate 
14427c478bd9Sstevel@tonic-gate 			(void) memset(&newstats, 0, sizeof (newstats));
14437c478bd9Sstevel@tonic-gate 			if (get_if_kstats(ifp, &newstats) == -1) {
14447c478bd9Sstevel@tonic-gate 				if (!(prev_complaints & COMP_NO_KSTATS))
14457c478bd9Sstevel@tonic-gate 					writelog(LOG_WARNING,
14467c478bd9Sstevel@tonic-gate 					    "unable to obtain kstats for %s",
14477c478bd9Sstevel@tonic-gate 					    phyi->phyi_name);
14487c478bd9Sstevel@tonic-gate 				complaints |= COMP_NO_KSTATS;
14497c478bd9Sstevel@tonic-gate 			}
14507c478bd9Sstevel@tonic-gate 
14517c478bd9Sstevel@tonic-gate 			/*
14527c478bd9Sstevel@tonic-gate 			 * If the interface just awoke, restart the counters.
14537c478bd9Sstevel@tonic-gate 			 */
14547c478bd9Sstevel@tonic-gate 			if (phyi->phyi_data.ts == 0) {
14557c478bd9Sstevel@tonic-gate 				phyi->phyi_data = newstats;
14567c478bd9Sstevel@tonic-gate 				continue;
14577c478bd9Sstevel@tonic-gate 			}
14587c478bd9Sstevel@tonic-gate 
14597c478bd9Sstevel@tonic-gate 			in = newstats.ipackets - phyi->phyi_data.ipackets;
14607c478bd9Sstevel@tonic-gate 			ierr = newstats.ierrors - phyi->phyi_data.ierrors;
14617c478bd9Sstevel@tonic-gate 			out = newstats.opackets - phyi->phyi_data.opackets;
14627c478bd9Sstevel@tonic-gate 			oerr = newstats.oerrors - phyi->phyi_data.oerrors;
14637c478bd9Sstevel@tonic-gate 			phyi->phyi_data = newstats;
14647c478bd9Sstevel@tonic-gate 
14657c478bd9Sstevel@tonic-gate 			/*
14667c478bd9Sstevel@tonic-gate 			 * Withhold judgment when the short error counters
14677c478bd9Sstevel@tonic-gate 			 * wrap, the interface is reset, or if there are
14687c478bd9Sstevel@tonic-gate 			 * no kstats.
14697c478bd9Sstevel@tonic-gate 			 */
14707c478bd9Sstevel@tonic-gate 			if (ierr < 0 || in < 0 || oerr < 0 || out < 0 ||
14717c478bd9Sstevel@tonic-gate 			    newstats.ts == 0) {
14727c478bd9Sstevel@tonic-gate 				LIM_SEC(ifscan_timer,
14737c478bd9Sstevel@tonic-gate 				    now.tv_sec + CHECK_BAD_INTERVAL);
14747c478bd9Sstevel@tonic-gate 				continue;
14757c478bd9Sstevel@tonic-gate 			}
14767c478bd9Sstevel@tonic-gate 
14777c478bd9Sstevel@tonic-gate 			/* Withhold judgement when there is no traffic */
14787c478bd9Sstevel@tonic-gate 			if (in == 0 && out == 0 && ierr == 0 && oerr == 0)
14797c478bd9Sstevel@tonic-gate 				continue;
14807c478bd9Sstevel@tonic-gate 
14817c478bd9Sstevel@tonic-gate 			/*
14827c478bd9Sstevel@tonic-gate 			 * It is bad if at least 25% of input or output on
14837c478bd9Sstevel@tonic-gate 			 * an interface results in errors.  Require
14847c478bd9Sstevel@tonic-gate 			 * presistent problems before marking it dead.
14857c478bd9Sstevel@tonic-gate 			 */
14867c478bd9Sstevel@tonic-gate 			if ((ierr > 0 && ierr >= in/4) ||
14877c478bd9Sstevel@tonic-gate 			    (oerr > 0 && oerr >= out/4)) {
14887c478bd9Sstevel@tonic-gate 				if (!(ifp->int_state & IS_SICK)) {
14897c478bd9Sstevel@tonic-gate 					trace_act("interface %s to %s"
14907c478bd9Sstevel@tonic-gate 					    " sick: in=%d ierr=%d"
14917c478bd9Sstevel@tonic-gate 					    " out=%d oerr=%d",
14927c478bd9Sstevel@tonic-gate 					    ifp->int_name,
14937c478bd9Sstevel@tonic-gate 					    naddr_ntoa(ifp->int_dstaddr),
14947c478bd9Sstevel@tonic-gate 					    in, ierr, out, oerr);
14957c478bd9Sstevel@tonic-gate 					if_sick(ifp, _B_TRUE);
14967c478bd9Sstevel@tonic-gate 					continue;
14977c478bd9Sstevel@tonic-gate 				}
14987c478bd9Sstevel@tonic-gate 				if (!(ifp->int_state & IS_BROKE)) {
14997c478bd9Sstevel@tonic-gate 					writelog(LOG_WARNING,
15007c478bd9Sstevel@tonic-gate 					    "interface %s to %s broken:"
15017c478bd9Sstevel@tonic-gate 					    " in=%d ierr=%d out=%d oerr=%d",
15027c478bd9Sstevel@tonic-gate 					    ifp->int_name,
15037c478bd9Sstevel@tonic-gate 					    naddr_ntoa(ifp->int_dstaddr),
15047c478bd9Sstevel@tonic-gate 					    in, ierr, out, oerr);
15057c478bd9Sstevel@tonic-gate 					if_bad(ifp, _B_TRUE);
15067c478bd9Sstevel@tonic-gate 				}
15077c478bd9Sstevel@tonic-gate 				continue;
15087c478bd9Sstevel@tonic-gate 			}
15097c478bd9Sstevel@tonic-gate 
15107c478bd9Sstevel@tonic-gate 			/* otherwise, it is active and healthy */
15117c478bd9Sstevel@tonic-gate 			ifp->int_act_time = now.tv_sec;
15127c478bd9Sstevel@tonic-gate 			if_ok(ifp, "", _B_TRUE);
15137c478bd9Sstevel@tonic-gate 			continue;
15147c478bd9Sstevel@tonic-gate 		}
15157c478bd9Sstevel@tonic-gate 
15167c478bd9Sstevel@tonic-gate 		/*
15177c478bd9Sstevel@tonic-gate 		 * This is a new interface.
15187c478bd9Sstevel@tonic-gate 		 * If it is dead, forget it.
15197c478bd9Sstevel@tonic-gate 		 */
15207c478bd9Sstevel@tonic-gate 		if (!IS_IFF_UP(ifs.int_if_flags))
15217c478bd9Sstevel@tonic-gate 			continue;
15227c478bd9Sstevel@tonic-gate 
15237c478bd9Sstevel@tonic-gate 		if (0 == (ifs.int_if_flags & (IFF_POINTOPOINT |
15247c478bd9Sstevel@tonic-gate 		    IFF_BROADCAST | IFF_LOOPBACK)) &&
15257c478bd9Sstevel@tonic-gate 		    !(ifs.int_state & IS_PASSIVE)) {
15267c478bd9Sstevel@tonic-gate 			if (!(prev_complaints & COMP_BAD_FLAGS))
15277c478bd9Sstevel@tonic-gate 				trace_act("%s is neither broadcast, "
15287c478bd9Sstevel@tonic-gate 				    "point-to-point, nor loopback",
15297c478bd9Sstevel@tonic-gate 				    ifs.int_name);
15307c478bd9Sstevel@tonic-gate 			complaints |= COMP_BAD_FLAGS;
15317c478bd9Sstevel@tonic-gate 			if (!(ifs.int_if_flags & IFF_MULTICAST))
15327c478bd9Sstevel@tonic-gate 				ifs.int_state |= IS_NO_RDISC;
15337c478bd9Sstevel@tonic-gate 		}
15347c478bd9Sstevel@tonic-gate 
15357c478bd9Sstevel@tonic-gate 
15367c478bd9Sstevel@tonic-gate 		/*
15377c478bd9Sstevel@tonic-gate 		 * It is new and ok.   Add it to the list of interfaces
15387c478bd9Sstevel@tonic-gate 		 */
15397c478bd9Sstevel@tonic-gate 		ifp = rtmalloc(sizeof (*ifp), "ifscan ifp");
15407c478bd9Sstevel@tonic-gate 		(void) memcpy(ifp, &ifs, sizeof (*ifp));
15417c478bd9Sstevel@tonic-gate 		get_parms(ifp);
15427c478bd9Sstevel@tonic-gate 		if_link(ifp, ifindex);
15437c478bd9Sstevel@tonic-gate 		trace_if("Add", ifp);
15447c478bd9Sstevel@tonic-gate 
15457c478bd9Sstevel@tonic-gate 		if (ifp->int_phys != NULL &&
15467c478bd9Sstevel@tonic-gate 		    get_if_kstats(ifp, &ifp->int_phys->phyi_data) == -1) {
15477c478bd9Sstevel@tonic-gate 			if (!(prev_complaints & COMP_NO_KSTATS))
15487c478bd9Sstevel@tonic-gate 				writelog(LOG_NOTICE,
15497c478bd9Sstevel@tonic-gate 				    "unable to obtain kstats for %s",
15507c478bd9Sstevel@tonic-gate 				    ifp->int_phys->phyi_name);
15517c478bd9Sstevel@tonic-gate 			complaints |= COMP_NO_KSTATS;
15527c478bd9Sstevel@tonic-gate 		}
15537c478bd9Sstevel@tonic-gate 
15547c478bd9Sstevel@tonic-gate 		/* Detect interfaces that have conflicting netmasks. */
15557c478bd9Sstevel@tonic-gate 		if (!(ifp->int_if_flags & (IFF_POINTOPOINT|IFF_LOOPBACK))) {
15567c478bd9Sstevel@tonic-gate 			for (ifp1 = ifnet; ifp1 != NULL;
15577c478bd9Sstevel@tonic-gate 			    ifp1 = ifp1->int_next) {
15587c478bd9Sstevel@tonic-gate 				if (ifp1->int_mask == ifp->int_mask)
15597c478bd9Sstevel@tonic-gate 					continue;
15607c478bd9Sstevel@tonic-gate 
15617c478bd9Sstevel@tonic-gate 				/*
15627c478bd9Sstevel@tonic-gate 				 * we don't care about point-to-point
15637c478bd9Sstevel@tonic-gate 				 * or loopback aliases
15647c478bd9Sstevel@tonic-gate 				 */
15657c478bd9Sstevel@tonic-gate 				if (ifp1->int_if_flags &
15667c478bd9Sstevel@tonic-gate 				    (IFF_POINTOPOINT|IFF_LOOPBACK)) {
15677c478bd9Sstevel@tonic-gate 					continue;
15687c478bd9Sstevel@tonic-gate 				}
15697c478bd9Sstevel@tonic-gate 
15707c478bd9Sstevel@tonic-gate 				/* ignore aliases on the same network */
15717c478bd9Sstevel@tonic-gate 				if (ifp->int_phys == ifp1->int_phys)
15727c478bd9Sstevel@tonic-gate 					continue;
15737c478bd9Sstevel@tonic-gate 
15747c478bd9Sstevel@tonic-gate 				if (on_net(ifp->int_addr,
15757c478bd9Sstevel@tonic-gate 				    ifp1->int_net, ifp1->int_mask) ||
15767c478bd9Sstevel@tonic-gate 				    on_net(ifp1->int_addr,
15777c478bd9Sstevel@tonic-gate 				    ifp->int_net, ifp->int_mask)) {
15787c478bd9Sstevel@tonic-gate 					writelog(LOG_INFO,
15797c478bd9Sstevel@tonic-gate 					    "possible netmask problem"
15807c478bd9Sstevel@tonic-gate 					    " between %s:%s and %s:%s",
15817c478bd9Sstevel@tonic-gate 					    ifp->int_name,
15827c478bd9Sstevel@tonic-gate 					    addrname(htonl(ifp->int_net),
15837c478bd9Sstevel@tonic-gate 					    ifp->int_mask, 1),
15847c478bd9Sstevel@tonic-gate 					    ifp1->int_name,
15857c478bd9Sstevel@tonic-gate 					    addrname(htonl(ifp1->int_net),
15867c478bd9Sstevel@tonic-gate 					    ifp1->int_mask, 1));
15877c478bd9Sstevel@tonic-gate 					complaints |= COMP_NETMASK;
15887c478bd9Sstevel@tonic-gate 				}
15897c478bd9Sstevel@tonic-gate 			}
15907c478bd9Sstevel@tonic-gate 		}
15917c478bd9Sstevel@tonic-gate 
15927c478bd9Sstevel@tonic-gate 		if (!(ifp->int_state & IS_DUP) &&
15937c478bd9Sstevel@tonic-gate 		    !IS_IFF_QUIET(ifp->int_if_flags)) {
15947c478bd9Sstevel@tonic-gate 			/* Count the # of directly connected networks. */
15957c478bd9Sstevel@tonic-gate 			tot_interfaces++;
15967c478bd9Sstevel@tonic-gate 			if (!IS_RIP_OFF(ifp->int_state))
15977c478bd9Sstevel@tonic-gate 				rip_interfaces++;
15987c478bd9Sstevel@tonic-gate 			if (!IS_RIP_OUT_OFF(ifp->int_state))
15997c478bd9Sstevel@tonic-gate 				ripout_interfaces++;
16007c478bd9Sstevel@tonic-gate 			if (IS_IFF_ROUTING(ifp->int_if_flags))
16017c478bd9Sstevel@tonic-gate 				fwd_interfaces++;
16027c478bd9Sstevel@tonic-gate 
16037c478bd9Sstevel@tonic-gate 			if_ok_rdisc(ifp);
16047c478bd9Sstevel@tonic-gate 			rip_on(ifp);
16057c478bd9Sstevel@tonic-gate 		}
16067c478bd9Sstevel@tonic-gate 	}
16077c478bd9Sstevel@tonic-gate 
16087c478bd9Sstevel@tonic-gate 	(void) close(sock);
16097c478bd9Sstevel@tonic-gate 
16107c478bd9Sstevel@tonic-gate 	/*
16117c478bd9Sstevel@tonic-gate 	 * If we are multi-homed and have at least two interfaces that
16127c478bd9Sstevel@tonic-gate 	 * are able to forward, then output RIP by default.
16137c478bd9Sstevel@tonic-gate 	 */
16147c478bd9Sstevel@tonic-gate 	if (!supplier_set)
16157c478bd9Sstevel@tonic-gate 		set_supplier();
16167c478bd9Sstevel@tonic-gate 
16177c478bd9Sstevel@tonic-gate 	/*
16187c478bd9Sstevel@tonic-gate 	 * If we are multi-homed, optionally advertise a route to
16197c478bd9Sstevel@tonic-gate 	 * our main address.
16207c478bd9Sstevel@tonic-gate 	 */
16217c478bd9Sstevel@tonic-gate 	if (advertise_mhome || (tot_interfaces > 1 && mhome)) {
16227c478bd9Sstevel@tonic-gate 		/* lookup myaddr if we haven't done so already */
16237c478bd9Sstevel@tonic-gate 		if (myaddr == 0) {
16247c478bd9Sstevel@tonic-gate 			char myname[MAXHOSTNAMELEN+1];
16257c478bd9Sstevel@tonic-gate 
16267c478bd9Sstevel@tonic-gate 			/*
16277c478bd9Sstevel@tonic-gate 			 * If we are unable to resolve our hostname, don't
16287c478bd9Sstevel@tonic-gate 			 * bother trying again.
16297c478bd9Sstevel@tonic-gate 			 */
16307c478bd9Sstevel@tonic-gate 			if (gethostname(myname, MAXHOSTNAMELEN) == -1) {
16317c478bd9Sstevel@tonic-gate 				msglog("gethostname: %s", rip_strerror(errno));
16327c478bd9Sstevel@tonic-gate 				advertise_mhome = _B_FALSE;
16337c478bd9Sstevel@tonic-gate 				mhome = _B_FALSE;
16347c478bd9Sstevel@tonic-gate 			} else if (gethost(myname, &myaddr) == 0) {
16357c478bd9Sstevel@tonic-gate 				writelog(LOG_WARNING,
16367c478bd9Sstevel@tonic-gate 				    "unable to resolve local hostname %s",
16377c478bd9Sstevel@tonic-gate 				    myname);
16387c478bd9Sstevel@tonic-gate 				advertise_mhome = _B_FALSE;
16397c478bd9Sstevel@tonic-gate 				mhome = _B_FALSE;
16407c478bd9Sstevel@tonic-gate 			}
16417c478bd9Sstevel@tonic-gate 		}
16427c478bd9Sstevel@tonic-gate 		if (myaddr != 0 &&
16437c478bd9Sstevel@tonic-gate 		    (ifp = ifwithaddr(myaddr, _B_FALSE, _B_FALSE)) != NULL &&
16447c478bd9Sstevel@tonic-gate 		    foundloopback) {
16457c478bd9Sstevel@tonic-gate 			advertise_mhome = _B_TRUE;
16467c478bd9Sstevel@tonic-gate 			rt = rtget(myaddr, HOST_MASK);
16477c478bd9Sstevel@tonic-gate 			if (rt != NULL) {
16487c478bd9Sstevel@tonic-gate 				if (rt->rt_ifp != ifp ||
16497c478bd9Sstevel@tonic-gate 				    rt->rt_router != loopaddr) {
16507c478bd9Sstevel@tonic-gate 					rtdelete(rt);
16517c478bd9Sstevel@tonic-gate 					rt = NULL;
16527c478bd9Sstevel@tonic-gate 				} else {
16537c478bd9Sstevel@tonic-gate 					loop_rts.rts_ifp = ifp;
16547c478bd9Sstevel@tonic-gate 					loop_rts.rts_metric = 0;
16557c478bd9Sstevel@tonic-gate 					loop_rts.rts_time = rt->rt_time;
16567c478bd9Sstevel@tonic-gate 					loop_rts.rts_origin = RO_LOOPBCK;
16577c478bd9Sstevel@tonic-gate 					rtchange(rt, rt->rt_state | RS_MHOME,
16587c478bd9Sstevel@tonic-gate 					    &loop_rts, NULL);
16597c478bd9Sstevel@tonic-gate 				}
16607c478bd9Sstevel@tonic-gate 			}
16617c478bd9Sstevel@tonic-gate 			if (rt == NULL) {
16627c478bd9Sstevel@tonic-gate 				loop_rts.rts_ifp = ifp;
16637c478bd9Sstevel@tonic-gate 				loop_rts.rts_metric = 0;
16647c478bd9Sstevel@tonic-gate 				loop_rts.rts_origin = RO_LOOPBCK;
16657c478bd9Sstevel@tonic-gate 				rtadd(myaddr, HOST_MASK, RS_MHOME, &loop_rts);
16667c478bd9Sstevel@tonic-gate 			}
16677c478bd9Sstevel@tonic-gate 		}
16687c478bd9Sstevel@tonic-gate 	}
16697c478bd9Sstevel@tonic-gate 
16707c478bd9Sstevel@tonic-gate 	for (ifp = ifnet; ifp != NULL; ifp = ifp1) {
16717c478bd9Sstevel@tonic-gate 		ifp1 = ifp->int_next;	/* because we may delete it */
16727c478bd9Sstevel@tonic-gate 
16737c478bd9Sstevel@tonic-gate 		/* Forget any interfaces that have disappeared. */
16747c478bd9Sstevel@tonic-gate 		if (!(ifp->int_state & (IS_CHECKED | IS_REMOTE))) {
16757c478bd9Sstevel@tonic-gate 			trace_act("interface %s has disappeared",
16767c478bd9Sstevel@tonic-gate 			    ifp->int_name);
16777c478bd9Sstevel@tonic-gate 			ifdel(ifp);
16787c478bd9Sstevel@tonic-gate 			continue;
16797c478bd9Sstevel@tonic-gate 		}
16807c478bd9Sstevel@tonic-gate 
16817c478bd9Sstevel@tonic-gate 		if ((ifp->int_state & IS_BROKE) &&
16827c478bd9Sstevel@tonic-gate 		    !(ifp->int_state & IS_PASSIVE))
16837c478bd9Sstevel@tonic-gate 			LIM_SEC(ifscan_timer, now.tv_sec+CHECK_BAD_INTERVAL);
16847c478bd9Sstevel@tonic-gate 
16857c478bd9Sstevel@tonic-gate 		/*
16867c478bd9Sstevel@tonic-gate 		 * If we ever have a RIPv1 interface, assume we always will.
16877c478bd9Sstevel@tonic-gate 		 * It might come back if it ever goes away.
16887c478bd9Sstevel@tonic-gate 		 */
16897c478bd9Sstevel@tonic-gate 		if (!(ifp->int_state & (IS_NO_RIPV1_OUT | IS_DUP)) &&
16907c478bd9Sstevel@tonic-gate 		    should_supply(ifp))
16917c478bd9Sstevel@tonic-gate 			have_ripv1_out = _B_TRUE;
16927c478bd9Sstevel@tonic-gate 		if (!(ifp->int_state & IS_NO_RIPV1_IN))
16937c478bd9Sstevel@tonic-gate 			have_ripv1_in = _B_TRUE;
16947c478bd9Sstevel@tonic-gate 	}
16957c478bd9Sstevel@tonic-gate 
16967c478bd9Sstevel@tonic-gate 	for (ifp = ifnet; ifp != NULL; ifp = ifp->int_next) {
16977c478bd9Sstevel@tonic-gate 		/*
16987c478bd9Sstevel@tonic-gate 		 * Ensure there is always a network route for interfaces,
16997c478bd9Sstevel@tonic-gate 		 * after any dead interfaces have been deleted, which
17007c478bd9Sstevel@tonic-gate 		 * might affect routes for point-to-point links.
17017c478bd9Sstevel@tonic-gate 		 */
17027c478bd9Sstevel@tonic-gate 		if (addrouteforif(ifp) == 0)
17037c478bd9Sstevel@tonic-gate 			continue;
17047c478bd9Sstevel@tonic-gate 
17057c478bd9Sstevel@tonic-gate 		/*
17067c478bd9Sstevel@tonic-gate 		 * Add routes to the local end of point-to-point interfaces
17077c478bd9Sstevel@tonic-gate 		 * using loopback.
17087c478bd9Sstevel@tonic-gate 		 */
17097c478bd9Sstevel@tonic-gate 		if ((ifp->int_if_flags & IFF_POINTOPOINT) &&
17107c478bd9Sstevel@tonic-gate 		    !(ifp->int_state & IS_REMOTE) && foundloopback) {
17117c478bd9Sstevel@tonic-gate 			/*
17127c478bd9Sstevel@tonic-gate 			 * Delete any routes to the network address through
17137c478bd9Sstevel@tonic-gate 			 * foreign routers. Remove even static routes.
17147c478bd9Sstevel@tonic-gate 			 */
17157c478bd9Sstevel@tonic-gate 			del_static(ifp->int_addr, HOST_MASK, 0, ifp, 0);
17167c478bd9Sstevel@tonic-gate 			rt = rtget(ifp->int_addr, HOST_MASK);
17177c478bd9Sstevel@tonic-gate 			if (rt != NULL && rt->rt_router != loopaddr) {
17187c478bd9Sstevel@tonic-gate 				rtdelete(rt);
17197c478bd9Sstevel@tonic-gate 				rt = NULL;
17207c478bd9Sstevel@tonic-gate 			}
17217c478bd9Sstevel@tonic-gate 			if (rt != NULL) {
17227c478bd9Sstevel@tonic-gate 				if (!(rt->rt_state & RS_LOCAL) ||
17237c478bd9Sstevel@tonic-gate 				    rt->rt_metric > ifp->int_metric) {
17247c478bd9Sstevel@tonic-gate 					ifp1 = ifp;
17257c478bd9Sstevel@tonic-gate 				} else {
17267c478bd9Sstevel@tonic-gate 					ifp1 = rt->rt_ifp;
17277c478bd9Sstevel@tonic-gate 				}
17287c478bd9Sstevel@tonic-gate 				loop_rts.rts_ifp = ifp1;
17297c478bd9Sstevel@tonic-gate 				loop_rts.rts_metric = 0;
17307c478bd9Sstevel@tonic-gate 				loop_rts.rts_time = rt->rt_time;
17317c478bd9Sstevel@tonic-gate 				loop_rts.rts_origin = RO_LOOPBCK;
17327c478bd9Sstevel@tonic-gate 				rtchange(rt, ((rt->rt_state & ~RS_NET_SYN) |
17337c478bd9Sstevel@tonic-gate 				    (RS_IF|RS_LOCAL)), &loop_rts, 0);
17347c478bd9Sstevel@tonic-gate 			} else {
17357c478bd9Sstevel@tonic-gate 				loop_rts.rts_ifp = ifp;
17367c478bd9Sstevel@tonic-gate 				loop_rts.rts_metric = 0;
17377c478bd9Sstevel@tonic-gate 				loop_rts.rts_origin = RO_LOOPBCK;
17387c478bd9Sstevel@tonic-gate 				rtadd(ifp->int_addr, HOST_MASK,
17397c478bd9Sstevel@tonic-gate 				    (RS_IF | RS_LOCAL), &loop_rts);
17407c478bd9Sstevel@tonic-gate 			}
17417c478bd9Sstevel@tonic-gate 		}
17427c478bd9Sstevel@tonic-gate 	}
17437c478bd9Sstevel@tonic-gate 
17447c478bd9Sstevel@tonic-gate 	/* add the authority routes */
17457c478bd9Sstevel@tonic-gate 	for (intnetp = intnets; intnetp != NULL;
17467c478bd9Sstevel@tonic-gate 	    intnetp = intnetp->intnet_next) {
17477c478bd9Sstevel@tonic-gate 		rt = rtget(intnetp->intnet_addr, intnetp->intnet_mask);
17487c478bd9Sstevel@tonic-gate 		if (rt != NULL &&
17497c478bd9Sstevel@tonic-gate 		    !(rt->rt_state & RS_NO_NET_SYN) &&
17507c478bd9Sstevel@tonic-gate 		    !(rt->rt_state & RS_NET_INT)) {
17517c478bd9Sstevel@tonic-gate 			rtdelete(rt);
17527c478bd9Sstevel@tonic-gate 			rt = NULL;
17537c478bd9Sstevel@tonic-gate 		}
17547c478bd9Sstevel@tonic-gate 		if (rt == NULL) {
17557c478bd9Sstevel@tonic-gate 			loop_rts.rts_ifp = NULL;
17567c478bd9Sstevel@tonic-gate 			loop_rts.rts_metric = intnetp->intnet_metric-1;
17577c478bd9Sstevel@tonic-gate 			loop_rts.rts_origin = RO_LOOPBCK;
17587c478bd9Sstevel@tonic-gate 			rtadd(intnetp->intnet_addr, intnetp->intnet_mask,
17597c478bd9Sstevel@tonic-gate 			    RS_NET_SYN | RS_NET_INT, &loop_rts);
17607c478bd9Sstevel@tonic-gate 		}
17617c478bd9Sstevel@tonic-gate 	}
17627c478bd9Sstevel@tonic-gate 
17637c478bd9Sstevel@tonic-gate 	prev_complaints = complaints;
17647c478bd9Sstevel@tonic-gate }
17657c478bd9Sstevel@tonic-gate 
17667c478bd9Sstevel@tonic-gate 
17677c478bd9Sstevel@tonic-gate static void
check_net_syn(struct interface * ifp)17687c478bd9Sstevel@tonic-gate check_net_syn(struct interface *ifp)
17697c478bd9Sstevel@tonic-gate {
17707c478bd9Sstevel@tonic-gate 	struct rt_entry *rt;
17717c478bd9Sstevel@tonic-gate 	struct rt_spare new;
17727c478bd9Sstevel@tonic-gate 
17737c478bd9Sstevel@tonic-gate 	/*
17747c478bd9Sstevel@tonic-gate 	 * Turn on the need to automatically synthesize a network route
17757c478bd9Sstevel@tonic-gate 	 * for this interface only if we are running RIPv1 on some other
17767c478bd9Sstevel@tonic-gate 	 * interface that is on a different class-A,B,or C network.
17777c478bd9Sstevel@tonic-gate 	 */
17787c478bd9Sstevel@tonic-gate 	if (have_ripv1_out || have_ripv1_in) {
17797c478bd9Sstevel@tonic-gate 		ifp->int_state |= IS_NEED_NET_SYN;
17807c478bd9Sstevel@tonic-gate 		rt = rtget(ifp->int_std_addr, ifp->int_std_mask);
17817c478bd9Sstevel@tonic-gate 		if (rt != NULL &&
17827c478bd9Sstevel@tonic-gate 		    0 == (rt->rt_state & RS_NO_NET_SYN) &&
17837c478bd9Sstevel@tonic-gate 		    (!(rt->rt_state & RS_NET_SYN) ||
17847c478bd9Sstevel@tonic-gate 		    rt->rt_metric > ifp->int_metric)) {
17857c478bd9Sstevel@tonic-gate 			rtdelete(rt);
17867c478bd9Sstevel@tonic-gate 			rt = NULL;
17877c478bd9Sstevel@tonic-gate 		}
17887c478bd9Sstevel@tonic-gate 		if (rt == NULL) {
17897c478bd9Sstevel@tonic-gate 			(void) memset(&new, 0, sizeof (new));
17907c478bd9Sstevel@tonic-gate 			new.rts_ifp = ifp;
17917c478bd9Sstevel@tonic-gate 			new.rts_gate = ifp->int_addr;
17927c478bd9Sstevel@tonic-gate 			new.rts_router = ifp->int_addr;
17937c478bd9Sstevel@tonic-gate 			new.rts_metric = ifp->int_metric;
17947c478bd9Sstevel@tonic-gate 			new.rts_origin = RO_NET_SYN;
17957c478bd9Sstevel@tonic-gate 			rtadd(ifp->int_std_addr, ifp->int_std_mask,
17967c478bd9Sstevel@tonic-gate 			    RS_NET_SYN, &new);
17977c478bd9Sstevel@tonic-gate 		}
17987c478bd9Sstevel@tonic-gate 
17997c478bd9Sstevel@tonic-gate 	} else {
18007c478bd9Sstevel@tonic-gate 		ifp->int_state &= ~IS_NEED_NET_SYN;
18017c478bd9Sstevel@tonic-gate 
18027c478bd9Sstevel@tonic-gate 		rt = rtget(ifp->int_std_addr, ifp->int_std_mask);
18037c478bd9Sstevel@tonic-gate 		if (rt != NULL &&
18047c478bd9Sstevel@tonic-gate 		    (rt->rt_state & RS_NET_SYN) &&
18057c478bd9Sstevel@tonic-gate 		    rt->rt_ifp == ifp)
18067c478bd9Sstevel@tonic-gate 			rtbad_sub(rt, NULL);
18077c478bd9Sstevel@tonic-gate 	}
18087c478bd9Sstevel@tonic-gate }
18097c478bd9Sstevel@tonic-gate 
18107c478bd9Sstevel@tonic-gate 
18117c478bd9Sstevel@tonic-gate /*
18127c478bd9Sstevel@tonic-gate  * Add route for interface if not currently installed.
18137c478bd9Sstevel@tonic-gate  * Create route to other end if a point-to-point link,
18147c478bd9Sstevel@tonic-gate  * otherwise a route to this (sub)network.
18157c478bd9Sstevel@tonic-gate  */
18167c478bd9Sstevel@tonic-gate static boolean_t			/* _B_FALSE=bad interface */
addrouteforif(struct interface * ifp)18177c478bd9Sstevel@tonic-gate addrouteforif(struct interface *ifp)
18187c478bd9Sstevel@tonic-gate {
18197c478bd9Sstevel@tonic-gate 	struct rt_entry *rt;
18207c478bd9Sstevel@tonic-gate 	struct rt_spare new;
18217c478bd9Sstevel@tonic-gate 	in_addr_t dst;
18227c478bd9Sstevel@tonic-gate 	uint16_t rt_newstate = RS_IF;
18237c478bd9Sstevel@tonic-gate 
18247c478bd9Sstevel@tonic-gate 
18257c478bd9Sstevel@tonic-gate 	/* skip sick interfaces */
18267c478bd9Sstevel@tonic-gate 	if (ifp->int_state & IS_BROKE)
18277c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
18287c478bd9Sstevel@tonic-gate 
18297c478bd9Sstevel@tonic-gate 	/*
18307c478bd9Sstevel@tonic-gate 	 * don't install routes for duplicate interfaces, or
18317c478bd9Sstevel@tonic-gate 	 * unnumbered point-to-point interfaces.
18327c478bd9Sstevel@tonic-gate 	 */
18337c478bd9Sstevel@tonic-gate 	if ((ifp->int_state & IS_DUP) ||
18347c478bd9Sstevel@tonic-gate 	    ((ifp->int_if_flags & IFF_POINTOPOINT) && ifp->int_dstaddr == 0))
18357c478bd9Sstevel@tonic-gate 		return (_B_TRUE);
18367c478bd9Sstevel@tonic-gate 
18377c478bd9Sstevel@tonic-gate 	/*
18387c478bd9Sstevel@tonic-gate 	 * If the interface on a subnet, then install a RIPv1 route to
18397c478bd9Sstevel@tonic-gate 	 * the network as well (unless it is sick).
18407c478bd9Sstevel@tonic-gate 	 */
18417c478bd9Sstevel@tonic-gate 	if (ifp->int_state & IS_SUBNET)
18427c478bd9Sstevel@tonic-gate 		check_net_syn(ifp);
18437c478bd9Sstevel@tonic-gate 
18447c478bd9Sstevel@tonic-gate 	dst = (0 != (ifp->int_if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) ?
18457c478bd9Sstevel@tonic-gate 	    ifp->int_dstaddr : htonl(ifp->int_net));
18467c478bd9Sstevel@tonic-gate 
18477c478bd9Sstevel@tonic-gate 	(void) memset(&new, 0, sizeof (new));
18487c478bd9Sstevel@tonic-gate 	new.rts_ifp = ifp;
18497c478bd9Sstevel@tonic-gate 	new.rts_router = ifp->int_addr;
18507c478bd9Sstevel@tonic-gate 	new.rts_gate = ifp->int_addr;
18517c478bd9Sstevel@tonic-gate 	new.rts_metric = ifp->int_metric;
18527c478bd9Sstevel@tonic-gate 	new.rts_time = now.tv_sec;
18537c478bd9Sstevel@tonic-gate 	if (ifp->int_if_flags & IFF_POINTOPOINT)
18547c478bd9Sstevel@tonic-gate 		new.rts_origin = RO_PTOPT;
18557c478bd9Sstevel@tonic-gate 	else if (ifp->int_if_flags & IFF_LOOPBACK)
18567c478bd9Sstevel@tonic-gate 		new.rts_origin = RO_LOOPBCK;
18577c478bd9Sstevel@tonic-gate 	else
18587c478bd9Sstevel@tonic-gate 		new.rts_origin = RO_IF;
18597c478bd9Sstevel@tonic-gate 
18607c478bd9Sstevel@tonic-gate 	/*
18617c478bd9Sstevel@tonic-gate 	 * If we are going to send packets to the gateway,
18627c478bd9Sstevel@tonic-gate 	 * it must be reachable using our physical interfaces
18637c478bd9Sstevel@tonic-gate 	 */
18647c478bd9Sstevel@tonic-gate 	if ((ifp->int_state & IS_REMOTE) &&
18657c478bd9Sstevel@tonic-gate 	    !(ifp->int_state & IS_EXTERNAL) &&
18667c478bd9Sstevel@tonic-gate 	    !check_remote(ifp))
18677c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
18687c478bd9Sstevel@tonic-gate 
18697c478bd9Sstevel@tonic-gate 	/*
18707c478bd9Sstevel@tonic-gate 	 * We are finished if the correct main interface route exists.
18717c478bd9Sstevel@tonic-gate 	 * The right route must be for the right interface, not synthesized
18727c478bd9Sstevel@tonic-gate 	 * from a subnet, be a "gateway" or not as appropriate, and so forth.
18737c478bd9Sstevel@tonic-gate 	 */
18747c478bd9Sstevel@tonic-gate 	del_static(dst, ifp->int_mask, 0, ifp, 0);
18757c478bd9Sstevel@tonic-gate 	rt = rtget(dst, ifp->int_mask);
18767c478bd9Sstevel@tonic-gate 	if (!IS_IFF_ROUTING(ifp->int_if_flags))
18777c478bd9Sstevel@tonic-gate 		rt_newstate |= RS_NOPROPAGATE;
18787c478bd9Sstevel@tonic-gate 	if (rt != NULL) {
18797c478bd9Sstevel@tonic-gate 		if ((rt->rt_ifp != ifp || rt->rt_router != ifp->int_addr) &&
18807c478bd9Sstevel@tonic-gate 		    (rt->rt_ifp == NULL ||
18817c478bd9Sstevel@tonic-gate 		    (rt->rt_ifp->int_state & IS_BROKE))) {
18827c478bd9Sstevel@tonic-gate 			rtdelete(rt);
18837c478bd9Sstevel@tonic-gate 			rt = NULL;
18847c478bd9Sstevel@tonic-gate 		} else {
18857c478bd9Sstevel@tonic-gate 			rtchange(rt, ((rt->rt_state | rt_newstate) &
18867c478bd9Sstevel@tonic-gate 			    ~(RS_NET_SYN | RS_LOCAL)), &new, 0);
18877c478bd9Sstevel@tonic-gate 		}
18887c478bd9Sstevel@tonic-gate 	}
18897c478bd9Sstevel@tonic-gate 	if (rt == NULL) {
18907c478bd9Sstevel@tonic-gate 		if (ifp->int_transitions++ > 0)
18917c478bd9Sstevel@tonic-gate 			trace_act("re-installing interface %s;"
18927c478bd9Sstevel@tonic-gate 			    " went up %d times",
18937c478bd9Sstevel@tonic-gate 			    ifp->int_name, ifp->int_transitions);
18947c478bd9Sstevel@tonic-gate 
18957c478bd9Sstevel@tonic-gate 		rtadd(dst, ifp->int_mask, rt_newstate, &new);
18967c478bd9Sstevel@tonic-gate 	}
18977c478bd9Sstevel@tonic-gate 
18987c478bd9Sstevel@tonic-gate 	return (_B_TRUE);
18997c478bd9Sstevel@tonic-gate }
19007c478bd9Sstevel@tonic-gate 
19017c478bd9Sstevel@tonic-gate /*
19027c478bd9Sstevel@tonic-gate  * Obtains the named kstat, and places its value in *value.  It
19037c478bd9Sstevel@tonic-gate  * returns 0 for success, -1 for failure.
19047c478bd9Sstevel@tonic-gate  */
19057c478bd9Sstevel@tonic-gate static int
kstat_named_value(kstat_t * ksp,char * name,uint32_t * value)19067c478bd9Sstevel@tonic-gate kstat_named_value(kstat_t *ksp, char *name, uint32_t *value)
19077c478bd9Sstevel@tonic-gate {
19087c478bd9Sstevel@tonic-gate 	kstat_named_t *knp;
19097c478bd9Sstevel@tonic-gate 
19107c478bd9Sstevel@tonic-gate 	if (ksp == NULL)
19117c478bd9Sstevel@tonic-gate 		return (-1);
19127c478bd9Sstevel@tonic-gate 
19137c478bd9Sstevel@tonic-gate 	if ((knp = kstat_data_lookup(ksp, name)) == NULL) {
19147c478bd9Sstevel@tonic-gate 		return (-1);
19157c478bd9Sstevel@tonic-gate 	} else if (knp->data_type != KSTAT_DATA_UINT32) {
19167c478bd9Sstevel@tonic-gate 		return (-1);
19177c478bd9Sstevel@tonic-gate 	} else {
19187c478bd9Sstevel@tonic-gate 		*value = knp->value.ui32;
19197c478bd9Sstevel@tonic-gate 		return (0);
19207c478bd9Sstevel@tonic-gate 	}
19217c478bd9Sstevel@tonic-gate }
19227c478bd9Sstevel@tonic-gate 
19237c478bd9Sstevel@tonic-gate static int
get_if_kstats(struct interface * ifp,struct phyi_data * newdata)19247c478bd9Sstevel@tonic-gate get_if_kstats(struct interface *ifp, struct phyi_data *newdata)
19257c478bd9Sstevel@tonic-gate {
19267c478bd9Sstevel@tonic-gate 	struct physical_interface *phyi = ifp->int_phys;
19277c478bd9Sstevel@tonic-gate 	kstat_ctl_t *kc;
19287c478bd9Sstevel@tonic-gate 	kstat_t *ksp;
19297c478bd9Sstevel@tonic-gate 
19307c478bd9Sstevel@tonic-gate 	/* We did this recently; don't do it again. */
19317c478bd9Sstevel@tonic-gate 	if (phyi->phyi_data.ts == now.tv_sec) {
19327c478bd9Sstevel@tonic-gate 		if (newdata != &phyi->phyi_data)
19337c478bd9Sstevel@tonic-gate 			*newdata = phyi->phyi_data;
19347c478bd9Sstevel@tonic-gate 		return (0);
19357c478bd9Sstevel@tonic-gate 	}
19367c478bd9Sstevel@tonic-gate 
19377c478bd9Sstevel@tonic-gate 	if ((kc = kstat_open()) == NULL)
19387c478bd9Sstevel@tonic-gate 		return (-1);
19397c478bd9Sstevel@tonic-gate 
1940d62bc4baSyz147064 	/*
1941d62bc4baSyz147064 	 * First we try to query the "link" kstats in case the link is renamed.
1942d62bc4baSyz147064 	 * If that fails, fallback to legacy ktats for those non-GLDv3 links.
1943d62bc4baSyz147064 	 */
1944d62bc4baSyz147064 	if (((ksp = kstat_lookup(kc, "link", 0, phyi->phyi_name)) == NULL) &&
1945d62bc4baSyz147064 	    ((ksp = kstat_lookup(kc, NULL, -1, phyi->phyi_name)) == NULL)) {
19467c478bd9Sstevel@tonic-gate 		(void) kstat_close(kc);
19477c478bd9Sstevel@tonic-gate 		return (-1);
19487c478bd9Sstevel@tonic-gate 	}
19497c478bd9Sstevel@tonic-gate 
19507c478bd9Sstevel@tonic-gate 	if (kstat_read(kc, ksp, NULL) == -1) {
19517c478bd9Sstevel@tonic-gate 		(void) kstat_close(kc);
19527c478bd9Sstevel@tonic-gate 		return (-1);
19537c478bd9Sstevel@tonic-gate 	}
19547c478bd9Sstevel@tonic-gate 
19557c478bd9Sstevel@tonic-gate 	if ((kstat_named_value(ksp, "ipackets", &newdata->ipackets) == -1) ||
19567c478bd9Sstevel@tonic-gate 	    (kstat_named_value(ksp, "opackets",	&newdata->opackets) == -1)) {
19577c478bd9Sstevel@tonic-gate 		newdata->ts = 0;
19587c478bd9Sstevel@tonic-gate 		(void) kstat_close(kc);
19597c478bd9Sstevel@tonic-gate 		return (-1);
19607c478bd9Sstevel@tonic-gate 	}
19617c478bd9Sstevel@tonic-gate 
19627c478bd9Sstevel@tonic-gate 	/* The loopback interface does not keep track of errors */
19637c478bd9Sstevel@tonic-gate 	if (!(ifp->int_if_flags & IFF_LOOPBACK)) {
19647c478bd9Sstevel@tonic-gate 		if ((kstat_named_value(ksp, "ierrors",
19657c478bd9Sstevel@tonic-gate 		    &newdata->ierrors) == -1) ||
19667c478bd9Sstevel@tonic-gate 		    (kstat_named_value(ksp, "oerrors",
19677c478bd9Sstevel@tonic-gate 		    &newdata->oerrors) == -1)) {
19687c478bd9Sstevel@tonic-gate 			newdata->ts = 0;
19697c478bd9Sstevel@tonic-gate 			(void) kstat_close(kc);
19707c478bd9Sstevel@tonic-gate 			return (-1);
19717c478bd9Sstevel@tonic-gate 		}
19727c478bd9Sstevel@tonic-gate 	}
19737c478bd9Sstevel@tonic-gate 
19747c478bd9Sstevel@tonic-gate 	newdata->ts = now.tv_sec;
19757c478bd9Sstevel@tonic-gate 	(void) kstat_close(kc);
19767c478bd9Sstevel@tonic-gate 	return (0);
19777c478bd9Sstevel@tonic-gate }
19787c478bd9Sstevel@tonic-gate 
19797c478bd9Sstevel@tonic-gate /*
19807c478bd9Sstevel@tonic-gate  * Returns true if we should supply routes to other systems.  If the
19817c478bd9Sstevel@tonic-gate  * user has forced us to be a supplier (by the command line) or if we
19827c478bd9Sstevel@tonic-gate  * have more than one forwarding interface and this is one of the
19837c478bd9Sstevel@tonic-gate  * forwarding interfaces, then behave as a RIP supplier (supply rdisc
19847c478bd9Sstevel@tonic-gate  * advertisements and RIP responses).
19857c478bd9Sstevel@tonic-gate  */
19867c478bd9Sstevel@tonic-gate boolean_t
should_supply(struct interface * ifp)19877c478bd9Sstevel@tonic-gate should_supply(struct interface *ifp)
19887c478bd9Sstevel@tonic-gate {
19897c478bd9Sstevel@tonic-gate 	if (ifp != NULL && !IS_IFF_ROUTING(ifp->int_if_flags))
19907c478bd9Sstevel@tonic-gate 		return (_B_FALSE);
19917c478bd9Sstevel@tonic-gate 	return ((supplier_set && supplier) ||
19927c478bd9Sstevel@tonic-gate 	    (!supplier_set && fwd_interfaces > 1));
19937c478bd9Sstevel@tonic-gate }
1994