xref: /onnv-gate/usr/src/cmd/cmd-inet/usr.sbin/in.routed/if.c (revision 7738:5a6ddac1e5d0)
10Sstevel@tonic-gate /*
25895Syz147064  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
30Sstevel@tonic-gate  * Use is subject to license terms.
40Sstevel@tonic-gate  *
50Sstevel@tonic-gate  * Copyright (c) 1983, 1993
60Sstevel@tonic-gate  *	The Regents of the University of California.  All rights reserved.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
90Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
100Sstevel@tonic-gate  * are met:
110Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
120Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
130Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
140Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in the
150Sstevel@tonic-gate  *    documentation and/or other materials provided with the distribution.
160Sstevel@tonic-gate  * 3. All advertising materials mentioning features or use of this software
170Sstevel@tonic-gate  *    must display the following acknowledgment:
180Sstevel@tonic-gate  *	This product includes software developed by the University of
190Sstevel@tonic-gate  *	California, Berkeley and its contributors.
200Sstevel@tonic-gate  * 4. Neither the name of the University nor the names of its contributors
210Sstevel@tonic-gate  *    may be used to endorse or promote products derived from this software
220Sstevel@tonic-gate  *    without specific prior written permission.
230Sstevel@tonic-gate  *
240Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
250Sstevel@tonic-gate  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
260Sstevel@tonic-gate  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
270Sstevel@tonic-gate  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
280Sstevel@tonic-gate  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
290Sstevel@tonic-gate  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
300Sstevel@tonic-gate  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
310Sstevel@tonic-gate  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
320Sstevel@tonic-gate  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
330Sstevel@tonic-gate  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
340Sstevel@tonic-gate  * SUCH DAMAGE.
350Sstevel@tonic-gate  *
360Sstevel@tonic-gate  * $FreeBSD: src/sbin/routed/if.c,v 1.8 2000/08/11 08:24:38 sheldonh Exp $
370Sstevel@tonic-gate  */
380Sstevel@tonic-gate 
390Sstevel@tonic-gate #include "defs.h"
400Sstevel@tonic-gate #include "pathnames.h"
410Sstevel@tonic-gate #include <sys/sockio.h>
420Sstevel@tonic-gate #include <inet/ip.h>
430Sstevel@tonic-gate #include <kstat.h>
440Sstevel@tonic-gate #include <stropts.h>
450Sstevel@tonic-gate #include <fcntl.h>
460Sstevel@tonic-gate #include <stddef.h>
470Sstevel@tonic-gate #include <assert.h>
480Sstevel@tonic-gate 
490Sstevel@tonic-gate /* linked list of all interfaces */
500Sstevel@tonic-gate struct interface *ifnet;
510Sstevel@tonic-gate 
520Sstevel@tonic-gate /*
530Sstevel@tonic-gate  * Acceptable sizes (in number of interfaces) for the interface hash
540Sstevel@tonic-gate  * tables.  These must all be prime.  The interface hash tables all
550Sstevel@tonic-gate  * start with a size of hash_table_sizes[0], and increase as needed.
560Sstevel@tonic-gate  */
570Sstevel@tonic-gate size_t hash_table_sizes[] = { 67, 131, 257, 521, 1031, 2053, 4099, 0 };
580Sstevel@tonic-gate 
590Sstevel@tonic-gate struct htbl {
600Sstevel@tonic-gate 	void		**htbl_ptrs;
610Sstevel@tonic-gate 	uint_t		(*htbl_hash)(const void *, size_t);
620Sstevel@tonic-gate 	size_t		htbl_link_off;	/* offset of the linkage structure */
630Sstevel@tonic-gate 	size_t		htbl_key_off;	/* offset of the key value (rehash) */
640Sstevel@tonic-gate 	size_t		htbl_size;	/* size of the hash */
650Sstevel@tonic-gate 	uint_t		htbl_size_index;
660Sstevel@tonic-gate 	uint_t		htbl_ifcount;	/* count of entries */
670Sstevel@tonic-gate 	boolean_t	htbl_grow;	/* growth allowed */
680Sstevel@tonic-gate };
690Sstevel@tonic-gate 
700Sstevel@tonic-gate /* Get first element -- for iteration */
710Sstevel@tonic-gate #define	HFIRST(htbl, arg) \
720Sstevel@tonic-gate 	((htbl)->htbl_ptrs[(htbl)->htbl_hash((arg), 0) % (htbl)->htbl_size])
730Sstevel@tonic-gate 
740Sstevel@tonic-gate /* Add an element to a hash */
750Sstevel@tonic-gate #define	HADD(htbl, strp) \
760Sstevel@tonic-gate 	hash_link((htbl), (htbl)->htbl_hash((strp), (htbl)->htbl_key_off), \
770Sstevel@tonic-gate 	    (strp))
780Sstevel@tonic-gate 
790Sstevel@tonic-gate uint_t	tot_interfaces;			/* # of remote and local interfaces */
800Sstevel@tonic-gate uint_t	rip_interfaces;			/* # of interfaces doing RIP */
810Sstevel@tonic-gate uint_t	ripout_interfaces;		/* # of interfaces advertising RIP */
820Sstevel@tonic-gate uint_t	fwd_interfaces;			/* # of interfaces ip_forwarding=1 */
830Sstevel@tonic-gate static boolean_t foundloopback;		/* valid flag for loopaddr */
840Sstevel@tonic-gate in_addr_t	loopaddr;		/* our address on loopback */
850Sstevel@tonic-gate static struct	rt_spare loop_rts;
860Sstevel@tonic-gate 
870Sstevel@tonic-gate struct timeval ifscan_timer;
880Sstevel@tonic-gate static struct timeval last_ifscan;
890Sstevel@tonic-gate #define	IF_RESCAN_DELAY() \
900Sstevel@tonic-gate 	(last_ifscan.tv_sec == now.tv_sec && \
910Sstevel@tonic-gate 	    last_ifscan.tv_usec == now.tv_usec && \
920Sstevel@tonic-gate 	    timercmp(&ifscan_timer, &now, > /* */))
930Sstevel@tonic-gate 
940Sstevel@tonic-gate boolean_t		have_ripv1_out;	/* have a RIPv1 interface */
950Sstevel@tonic-gate static boolean_t	have_ripv1_in;
960Sstevel@tonic-gate 
970Sstevel@tonic-gate static void		if_bad(struct interface *, boolean_t);
980Sstevel@tonic-gate static boolean_t	addrouteforif(struct interface *);
990Sstevel@tonic-gate static int	get_if_kstats(struct interface *, struct phyi_data *);
1000Sstevel@tonic-gate static uint_t	ahash(const void *, uint_t);
1010Sstevel@tonic-gate static uint_t	ihash(const void *, uint_t);
1020Sstevel@tonic-gate static uint_t	nhash(const void *, uint_t);
1030Sstevel@tonic-gate static void	htbl_grow(struct htbl *);
1040Sstevel@tonic-gate 
1050Sstevel@tonic-gate /*
1060Sstevel@tonic-gate  * Table of all interfaces, hashed by interface address.  For remote
1070Sstevel@tonic-gate  * interfaces, the gateway address is used.
1080Sstevel@tonic-gate  */
1090Sstevel@tonic-gate static struct htbl ahash_tbl = {
1100Sstevel@tonic-gate     NULL, ahash, offsetof(struct interface, int_ahash),
1110Sstevel@tonic-gate     offsetof(struct interface, int_addr),
1120Sstevel@tonic-gate     0, 0, 0, _B_TRUE };
1130Sstevel@tonic-gate /*
1140Sstevel@tonic-gate  * Table of broadcast capable interfaces, hashed by interface broadcast
1150Sstevel@tonic-gate  * address.
1160Sstevel@tonic-gate  */
1170Sstevel@tonic-gate static struct htbl bhash_tbl = {
1180Sstevel@tonic-gate     NULL, ahash, offsetof(struct interface, int_bhash),
1190Sstevel@tonic-gate     offsetof(struct interface, int_brdaddr),
1200Sstevel@tonic-gate     0, 0, 0, _B_TRUE };
1210Sstevel@tonic-gate /*
1220Sstevel@tonic-gate  * Table of physical_interface structures (lists of interfaces by ifIndex),
1230Sstevel@tonic-gate  * hashed by interface index.
1240Sstevel@tonic-gate  */
1250Sstevel@tonic-gate static struct htbl ihash_tbl = {
1260Sstevel@tonic-gate     NULL, ihash, offsetof(struct physical_interface, phyi_link),
1270Sstevel@tonic-gate     offsetof(struct physical_interface, phyi_index),
1280Sstevel@tonic-gate     0, 0, 0, _B_TRUE };
1290Sstevel@tonic-gate /*
1300Sstevel@tonic-gate  * Table of all interfaces, hashed by interface name.
1310Sstevel@tonic-gate  */
1320Sstevel@tonic-gate static struct htbl nhash_tbl = {
1330Sstevel@tonic-gate     NULL, nhash, offsetof(struct interface, int_nhash),
1340Sstevel@tonic-gate     offsetof(struct interface, int_name),
1350Sstevel@tonic-gate     0, 0, 0, _B_TRUE };
1360Sstevel@tonic-gate 
1370Sstevel@tonic-gate static struct physical_interface dummy_phyi;
1380Sstevel@tonic-gate struct interface dummy_ifp;
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate /* Hash based on an IP address. */
1410Sstevel@tonic-gate static uint_t
ahash(const void * arg,size_t voffs)1420Sstevel@tonic-gate ahash(const void *arg, size_t voffs)
1430Sstevel@tonic-gate {
1440Sstevel@tonic-gate 	/* LINTED */
1450Sstevel@tonic-gate 	return ((uint_t)*(const in_addr_t *)((const char *)arg + voffs));
1460Sstevel@tonic-gate }
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate static uint_t
ihash(const void * arg,size_t voffs)1490Sstevel@tonic-gate ihash(const void *arg, size_t voffs)
1500Sstevel@tonic-gate {
1510Sstevel@tonic-gate 	/* LINTED */
1520Sstevel@tonic-gate 	return ((uint_t)*(const uint32_t *)((const char *)arg + voffs));
1530Sstevel@tonic-gate }
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate static uint_t
nhash(const void * arg,size_t voffs)1560Sstevel@tonic-gate nhash(const void *arg, size_t voffs)
1570Sstevel@tonic-gate {
1580Sstevel@tonic-gate 	const char *cp = (const char *)arg + voffs;
1590Sstevel@tonic-gate 	uint_t i;
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate 	for (i = 0; *cp != '\0'; cp++) {
1620Sstevel@tonic-gate 		i = ((i<<1) & 0x7fffffff) | ((i>>30) & 0x00000003);
1630Sstevel@tonic-gate 		i ^= *cp;
1640Sstevel@tonic-gate 	}
1650Sstevel@tonic-gate 	return (i);
1660Sstevel@tonic-gate }
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate /*
1690Sstevel@tonic-gate  * Add an element to the head of the list.
1700Sstevel@tonic-gate  */
1710Sstevel@tonic-gate static void
link_in(void ** head,void * strp,size_t loffs)1720Sstevel@tonic-gate link_in(void **head, void *strp, size_t loffs)
1730Sstevel@tonic-gate {
1740Sstevel@tonic-gate 	struct hlinkage *hlp;
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate 	/* LINTED: alignment known to be good. */
1770Sstevel@tonic-gate 	hlp = (struct hlinkage *)((char *)strp + loffs);
1780Sstevel@tonic-gate 	hlp->hl_prev = head;
1790Sstevel@tonic-gate 	if ((hlp->hl_next = *head) != NULL) {
1800Sstevel@tonic-gate 		/* LINTED */
1810Sstevel@tonic-gate 		((struct hlinkage *)((char *)*head + loffs))->hl_prev =
1820Sstevel@tonic-gate 		    &hlp->hl_next;
1830Sstevel@tonic-gate 	}
1840Sstevel@tonic-gate 	*head = strp;
1850Sstevel@tonic-gate }
1860Sstevel@tonic-gate 
1870Sstevel@tonic-gate /* Remove from a list */
1880Sstevel@tonic-gate static void
link_out(void * strp,size_t loffs)1890Sstevel@tonic-gate link_out(void *strp, size_t loffs)
1900Sstevel@tonic-gate {
1910Sstevel@tonic-gate 	struct hlinkage *hlp;
1920Sstevel@tonic-gate 
1930Sstevel@tonic-gate 	/* LINTED: alignment known to be good. */
1940Sstevel@tonic-gate 	hlp = (struct hlinkage *)((char *)strp + loffs);
1950Sstevel@tonic-gate 	if ((*hlp->hl_prev = hlp->hl_next) != NULL) {
1960Sstevel@tonic-gate 		/* LINTED */
1970Sstevel@tonic-gate 		((struct hlinkage *)((char *)hlp->hl_next + loffs))->hl_prev =
1980Sstevel@tonic-gate 		    hlp->hl_prev;
1990Sstevel@tonic-gate 	}
2000Sstevel@tonic-gate }
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate /* Add to a hash */
2030Sstevel@tonic-gate static void
hash_link(struct htbl * htbl,uint_t hval,void * strp)2040Sstevel@tonic-gate hash_link(struct htbl *htbl, uint_t hval, void *strp)
2050Sstevel@tonic-gate {
2060Sstevel@tonic-gate 	void **hep;
2070Sstevel@tonic-gate 
2080Sstevel@tonic-gate 	if (htbl->htbl_grow && htbl->htbl_ifcount >= htbl->htbl_size * 5)
2090Sstevel@tonic-gate 		htbl_grow(htbl);
2100Sstevel@tonic-gate 
2110Sstevel@tonic-gate 	hep = &htbl->htbl_ptrs[hval % htbl->htbl_size];
2120Sstevel@tonic-gate 	link_in(hep, strp, htbl->htbl_link_off);
2130Sstevel@tonic-gate 	htbl->htbl_ifcount++;
2140Sstevel@tonic-gate }
2150Sstevel@tonic-gate 
2160Sstevel@tonic-gate /* Remove from a hash */
2170Sstevel@tonic-gate static void
hash_unlink(struct htbl * htbl,void * strp)2180Sstevel@tonic-gate hash_unlink(struct htbl *htbl, void *strp)
2190Sstevel@tonic-gate {
2200Sstevel@tonic-gate 	link_out(strp, htbl->htbl_link_off);
2210Sstevel@tonic-gate 	htbl->htbl_ifcount--;
2220Sstevel@tonic-gate }
2230Sstevel@tonic-gate 
2240Sstevel@tonic-gate static void
dummy_ifp_init(void)2250Sstevel@tonic-gate dummy_ifp_init(void)
2260Sstevel@tonic-gate {
2270Sstevel@tonic-gate 	dummy_phyi.phyi_interface = &dummy_ifp;
2280Sstevel@tonic-gate 	dummy_ifp.int_phys = &dummy_phyi;
2290Sstevel@tonic-gate 	(void) strcpy(dummy_phyi.phyi_name, "wildcard");
2300Sstevel@tonic-gate 	(void) strcpy(dummy_ifp.int_name, "wildcard");
2310Sstevel@tonic-gate 	dummy_ifp.int_dstaddr = dummy_ifp.int_addr = INADDR_NONE;
2320Sstevel@tonic-gate 	dummy_ifp.int_mask = IP_HOST_MASK;
2330Sstevel@tonic-gate 	dummy_ifp.int_metric = HOPCNT_INFINITY;
2340Sstevel@tonic-gate 	dummy_ifp.int_state = (IS_BROKE|IS_PASSIVE|IS_NO_RIP|IS_NO_RDISC);
2350Sstevel@tonic-gate 	dummy_ifp.int_std_mask = std_mask(dummy_ifp.int_addr);
2360Sstevel@tonic-gate 	dummy_ifp.int_std_net = dummy_ifp.int_net & dummy_ifp.int_std_mask;
2370Sstevel@tonic-gate 	dummy_ifp.int_std_addr = htonl(dummy_ifp.int_std_net);
2380Sstevel@tonic-gate }
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate /* allocate the interface hash tables */
2410Sstevel@tonic-gate void
iftbl_alloc(void)2420Sstevel@tonic-gate iftbl_alloc(void)
2430Sstevel@tonic-gate {
2440Sstevel@tonic-gate 	size_t initial_size = hash_table_sizes[0];
2450Sstevel@tonic-gate 
2460Sstevel@tonic-gate 	errno = 0;
2470Sstevel@tonic-gate 	ahash_tbl.htbl_ptrs = calloc(initial_size, sizeof (void *));
2480Sstevel@tonic-gate 	bhash_tbl.htbl_ptrs = calloc(initial_size, sizeof (void *));
2490Sstevel@tonic-gate 	ihash_tbl.htbl_ptrs = calloc(initial_size, sizeof (void *));
2500Sstevel@tonic-gate 	nhash_tbl.htbl_ptrs = calloc(initial_size, sizeof (void *));
2510Sstevel@tonic-gate 
2520Sstevel@tonic-gate 	if (errno != 0)
2530Sstevel@tonic-gate 		BADERR(_B_FALSE, "Unable to allocate interface tables");
2540Sstevel@tonic-gate 
2550Sstevel@tonic-gate 	ahash_tbl.htbl_size = initial_size;
2560Sstevel@tonic-gate 	bhash_tbl.htbl_size = initial_size;
2570Sstevel@tonic-gate 	ihash_tbl.htbl_size = initial_size;
2580Sstevel@tonic-gate 	nhash_tbl.htbl_size = initial_size;
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate 	dummy_ifp_init();
2610Sstevel@tonic-gate }
2620Sstevel@tonic-gate 
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate static void
htbl_grow(struct htbl * htbl)2650Sstevel@tonic-gate htbl_grow(struct htbl *htbl)
2660Sstevel@tonic-gate {
2670Sstevel@tonic-gate 	void *strp;
2680Sstevel@tonic-gate 	void **new_ptrs, **saved_old_ptrs, **old_ptrs;
2690Sstevel@tonic-gate 	size_t new_size, old_size;
2700Sstevel@tonic-gate 	static uint_t failed_count;
2710Sstevel@tonic-gate 
2720Sstevel@tonic-gate 	if ((new_size = hash_table_sizes[htbl->htbl_size_index + 1]) == 0)
2730Sstevel@tonic-gate 		return;
2740Sstevel@tonic-gate 
2750Sstevel@tonic-gate 	if ((new_ptrs = calloc(new_size, sizeof (void *))) == NULL) {
2760Sstevel@tonic-gate 		/*
2770Sstevel@tonic-gate 		 * This is not fatal since we already have a
2780Sstevel@tonic-gate 		 * functional, yet crowded, interface table.
2790Sstevel@tonic-gate 		 */
2800Sstevel@tonic-gate 		if (++failed_count % 100 == 1)
2810Sstevel@tonic-gate 			msglog("%sunable to grow interface hash table: %s",
2820Sstevel@tonic-gate 			    failed_count > 1 ? "Still " : "",
2830Sstevel@tonic-gate 			    rip_strerror(errno));
2840Sstevel@tonic-gate 		return;
2850Sstevel@tonic-gate 	}
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate 	failed_count = 0;
2880Sstevel@tonic-gate 
2890Sstevel@tonic-gate 	saved_old_ptrs = old_ptrs = htbl->htbl_ptrs;
2900Sstevel@tonic-gate 	old_size = htbl->htbl_size;
2910Sstevel@tonic-gate 	htbl->htbl_ptrs = new_ptrs;
2920Sstevel@tonic-gate 	htbl->htbl_size = new_size;
2930Sstevel@tonic-gate 	htbl->htbl_size_index++;
2940Sstevel@tonic-gate 	htbl->htbl_ifcount = 0;
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate 	/*
2970Sstevel@tonic-gate 	 * Go through the list of structures, and re-link each into
2980Sstevel@tonic-gate 	 * this new table.
2990Sstevel@tonic-gate 	 */
3000Sstevel@tonic-gate 	htbl->htbl_grow = _B_FALSE;
3010Sstevel@tonic-gate 	while (old_size-- > 0) {
3020Sstevel@tonic-gate 		strp = *old_ptrs++;
3030Sstevel@tonic-gate 		HADD(htbl, strp);
3040Sstevel@tonic-gate 	}
3050Sstevel@tonic-gate 
3060Sstevel@tonic-gate 	htbl->htbl_grow = _B_TRUE;
3070Sstevel@tonic-gate 	free(saved_old_ptrs);
3080Sstevel@tonic-gate }
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate /* Link a new interface into the lists and hash tables. */
3110Sstevel@tonic-gate void
if_link(struct interface * ifp,uint32_t ifindex)3120Sstevel@tonic-gate if_link(struct interface *ifp, uint32_t ifindex)
3130Sstevel@tonic-gate {
3140Sstevel@tonic-gate 	struct physical_interface *phyi;
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate 	link_in((void **)&ifnet, ifp, offsetof(struct interface, int_link));
3170Sstevel@tonic-gate 
3180Sstevel@tonic-gate 	HADD(&ahash_tbl, ifp);
3190Sstevel@tonic-gate 	HADD(&nhash_tbl, ifp);
3200Sstevel@tonic-gate 
3210Sstevel@tonic-gate 	if (ifp->int_if_flags & IFF_BROADCAST)
3220Sstevel@tonic-gate 		HADD(&bhash_tbl, ifp);
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate 	if (ifindex != 0) {
3250Sstevel@tonic-gate 		for (phyi = HFIRST(&ihash_tbl, &ifindex);
3260Sstevel@tonic-gate 		    phyi != NULL; phyi = phyi->phyi_link.hl_next) {
3270Sstevel@tonic-gate 			if (phyi->phyi_index == ifindex)
3280Sstevel@tonic-gate 				break;
3290Sstevel@tonic-gate 		}
3300Sstevel@tonic-gate 		if (phyi == NULL) {
3310Sstevel@tonic-gate 			size_t size;
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate 			phyi = rtmalloc(sizeof (*phyi), "physical_interface");
3340Sstevel@tonic-gate 			(void) memset(phyi, 0, sizeof (*phyi));
3350Sstevel@tonic-gate 			phyi->phyi_index = ifindex;
3360Sstevel@tonic-gate 			/* LINTED */
3370Sstevel@tonic-gate 			assert(IF_NAME_LEN >= IF_NAMESIZE);
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate 			size = strcspn(ifp->int_name, ":");
3400Sstevel@tonic-gate 			(void) strncpy(phyi->phyi_name, ifp->int_name,
3410Sstevel@tonic-gate 			    size);
3420Sstevel@tonic-gate 			phyi->phyi_name[size] = '\0';
3430Sstevel@tonic-gate 			HADD(&ihash_tbl, phyi);
3440Sstevel@tonic-gate 		}
3450Sstevel@tonic-gate 		link_in((void **)&phyi->phyi_interface, ifp,
3460Sstevel@tonic-gate 		    offsetof(struct interface, int_ilist));
3470Sstevel@tonic-gate 		ifp->int_phys = phyi;
3480Sstevel@tonic-gate 	}
3490Sstevel@tonic-gate }
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate /* Find the interface with an address */
3520Sstevel@tonic-gate struct interface *
ifwithaddr(in_addr_t addr,boolean_t bcast,boolean_t remote)3530Sstevel@tonic-gate ifwithaddr(in_addr_t addr,
3540Sstevel@tonic-gate     boolean_t bcast,	/* notice IFF_BROADCAST address */
3550Sstevel@tonic-gate     boolean_t remote)	/* include IS_REMOTE interfaces */
3560Sstevel@tonic-gate {
3570Sstevel@tonic-gate 	struct interface *ifp, *possible = NULL;
3580Sstevel@tonic-gate 	uint32_t remote_state;
3590Sstevel@tonic-gate 
3600Sstevel@tonic-gate 	remote_state = (!remote ? IS_REMOTE : 0);
3610Sstevel@tonic-gate 
3620Sstevel@tonic-gate 	for (ifp = HFIRST(&ahash_tbl, &addr); ifp != NULL;
3630Sstevel@tonic-gate 	    ifp = ifp->int_ahash.hl_next) {
3640Sstevel@tonic-gate 		if (ifp->int_addr != addr)
3650Sstevel@tonic-gate 			continue;
3660Sstevel@tonic-gate 		if (ifp->int_state & remote_state)
3670Sstevel@tonic-gate 			continue;
3680Sstevel@tonic-gate 		if (!(ifp->int_state & (IS_BROKE | IS_PASSIVE)))
3690Sstevel@tonic-gate 			return (ifp);
3700Sstevel@tonic-gate 		possible = ifp;
3710Sstevel@tonic-gate 	}
3720Sstevel@tonic-gate 
3730Sstevel@tonic-gate 	if (possible != NULL || !bcast)
3740Sstevel@tonic-gate 		return (possible);
3750Sstevel@tonic-gate 
3760Sstevel@tonic-gate 	for (ifp = HFIRST(&bhash_tbl, &addr); ifp != NULL;
3770Sstevel@tonic-gate 	    ifp = ifp->int_bhash.hl_next) {
3780Sstevel@tonic-gate 		if (ifp->int_brdaddr != addr)
3790Sstevel@tonic-gate 			continue;
3800Sstevel@tonic-gate 		if (ifp->int_state & remote_state)
3810Sstevel@tonic-gate 			continue;
3820Sstevel@tonic-gate 		if (!(ifp->int_state & (IS_BROKE | IS_PASSIVE)))
3830Sstevel@tonic-gate 			return (ifp);
3840Sstevel@tonic-gate 		possible = ifp;
3850Sstevel@tonic-gate 	}
3860Sstevel@tonic-gate 
3870Sstevel@tonic-gate 	return (possible);
3880Sstevel@tonic-gate }
3890Sstevel@tonic-gate 
3900Sstevel@tonic-gate 
3910Sstevel@tonic-gate /* find the interface with the specified name ("hme0" for example) */
3920Sstevel@tonic-gate struct interface *
ifwithname(const char * name)3930Sstevel@tonic-gate ifwithname(const char *name)
3940Sstevel@tonic-gate {
3950Sstevel@tonic-gate 	struct interface *ifp;
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate 	for (;;) {
3980Sstevel@tonic-gate 		for (ifp = HFIRST(&nhash_tbl, name); ifp != NULL;
3990Sstevel@tonic-gate 		    ifp = ifp->int_nhash.hl_next) {
4000Sstevel@tonic-gate 			if (strcmp(ifp->int_name, name) == 0)
4010Sstevel@tonic-gate 				return (ifp);
4020Sstevel@tonic-gate 		}
4030Sstevel@tonic-gate 
4040Sstevel@tonic-gate 		/*
4050Sstevel@tonic-gate 		 * If there is no known interface, maybe there is a
4060Sstevel@tonic-gate 		 * new interface.  So just once look for new interfaces.
4070Sstevel@tonic-gate 		 */
4080Sstevel@tonic-gate 		if (IF_RESCAN_DELAY())
4090Sstevel@tonic-gate 			return (NULL);
4100Sstevel@tonic-gate 		ifscan();
4110Sstevel@tonic-gate 	}
4120Sstevel@tonic-gate }
4130Sstevel@tonic-gate 
414*7738SRishi.Srivatsavai@Sun.COM /* Return physical interface with the specified name */
415*7738SRishi.Srivatsavai@Sun.COM struct physical_interface *
phys_byname(const char * name)416*7738SRishi.Srivatsavai@Sun.COM phys_byname(const char *name)
417*7738SRishi.Srivatsavai@Sun.COM {
418*7738SRishi.Srivatsavai@Sun.COM 	int nlen;
419*7738SRishi.Srivatsavai@Sun.COM 	size_t i;
420*7738SRishi.Srivatsavai@Sun.COM 	struct physical_interface *phyi;
421*7738SRishi.Srivatsavai@Sun.COM 
422*7738SRishi.Srivatsavai@Sun.COM 	nlen = strcspn(name, ":");
423*7738SRishi.Srivatsavai@Sun.COM 	for (i = 0; i < ihash_tbl.htbl_size; i++) {
424*7738SRishi.Srivatsavai@Sun.COM 		for (phyi = ihash_tbl.htbl_ptrs[i]; phyi != NULL;
425*7738SRishi.Srivatsavai@Sun.COM 		    phyi = phyi->phyi_link.hl_next) {
426*7738SRishi.Srivatsavai@Sun.COM 			if (strncmp(phyi->phyi_name, name, nlen) == 0 &&
427*7738SRishi.Srivatsavai@Sun.COM 			    phyi->phyi_name[nlen] == '\0')
428*7738SRishi.Srivatsavai@Sun.COM 				return (phyi);
429*7738SRishi.Srivatsavai@Sun.COM 		}
430*7738SRishi.Srivatsavai@Sun.COM 	}
431*7738SRishi.Srivatsavai@Sun.COM 	return (NULL);
432*7738SRishi.Srivatsavai@Sun.COM }
433*7738SRishi.Srivatsavai@Sun.COM 
4340Sstevel@tonic-gate struct interface *
findremoteif(in_addr_t addr)4350Sstevel@tonic-gate findremoteif(in_addr_t addr)
4360Sstevel@tonic-gate {
4370Sstevel@tonic-gate 	struct interface *ifp;
4380Sstevel@tonic-gate 
4390Sstevel@tonic-gate 	for (ifp = HFIRST(&ahash_tbl, &addr); ifp != NULL;
4400Sstevel@tonic-gate 	    ifp = ifp->int_ahash.hl_next) {
4410Sstevel@tonic-gate 		if ((ifp->int_state & IS_REMOTE) && ifp->int_addr == addr)
4420Sstevel@tonic-gate 			return (ifp);
4430Sstevel@tonic-gate 	}
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate 	return (NULL);
4460Sstevel@tonic-gate }
4470Sstevel@tonic-gate 
4480Sstevel@tonic-gate struct interface *
findifaddr(in_addr_t addr)4490Sstevel@tonic-gate findifaddr(in_addr_t addr)
4500Sstevel@tonic-gate {
4510Sstevel@tonic-gate 	struct interface *ifp;
4520Sstevel@tonic-gate 
4530Sstevel@tonic-gate 	for (ifp = HFIRST(&ahash_tbl, &addr); ifp != NULL;
4540Sstevel@tonic-gate 	    ifp = ifp->int_ahash.hl_next) {
4550Sstevel@tonic-gate 		if (ifp->int_addr == addr)
4560Sstevel@tonic-gate 			return (ifp);
4570Sstevel@tonic-gate 	}
4580Sstevel@tonic-gate 
4590Sstevel@tonic-gate 	return (NULL);
4600Sstevel@tonic-gate }
4610Sstevel@tonic-gate 
4620Sstevel@tonic-gate /*
4630Sstevel@tonic-gate  * Return the first interface with the given index.
4640Sstevel@tonic-gate  */
4650Sstevel@tonic-gate struct interface *
ifwithindex(ulong_t index,boolean_t rescan_ok)4660Sstevel@tonic-gate ifwithindex(ulong_t index,
4670Sstevel@tonic-gate     boolean_t rescan_ok)
4680Sstevel@tonic-gate {
4690Sstevel@tonic-gate 	struct physical_interface *phyi;
4700Sstevel@tonic-gate 
4710Sstevel@tonic-gate 	for (;;) {
4720Sstevel@tonic-gate 		for (phyi = HFIRST(&ihash_tbl, &index); phyi != NULL;
4730Sstevel@tonic-gate 		    phyi = phyi->phyi_link.hl_next) {
4740Sstevel@tonic-gate 			if (phyi->phyi_index == index)
4750Sstevel@tonic-gate 				return (phyi->phyi_interface);
4760Sstevel@tonic-gate 		}
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate 		/*
4790Sstevel@tonic-gate 		 * If there is no known interface, maybe there is a
4800Sstevel@tonic-gate 		 * new interface.  So just once look for new interfaces.
4810Sstevel@tonic-gate 		 */
4820Sstevel@tonic-gate 		if (!rescan_ok || IF_RESCAN_DELAY())
4830Sstevel@tonic-gate 			return (NULL);
4840Sstevel@tonic-gate 		rescan_ok = _B_FALSE;
4850Sstevel@tonic-gate 		ifscan();
4860Sstevel@tonic-gate 	}
4870Sstevel@tonic-gate }
4880Sstevel@tonic-gate 
489*7738SRishi.Srivatsavai@Sun.COM /*
490*7738SRishi.Srivatsavai@Sun.COM  * Returns true only if given ifp has the exact address else returns
491*7738SRishi.Srivatsavai@Sun.COM  * false and sets best if an ifp matches partially and is a better
492*7738SRishi.Srivatsavai@Sun.COM  * match than the previous one passed via best.
493*7738SRishi.Srivatsavai@Sun.COM  */
494*7738SRishi.Srivatsavai@Sun.COM boolean_t
addr_on_ifp(in_addr_t addr,struct interface * ifp,struct interface ** best)495*7738SRishi.Srivatsavai@Sun.COM addr_on_ifp(in_addr_t addr, struct interface *ifp,
496*7738SRishi.Srivatsavai@Sun.COM     struct interface **best)
497*7738SRishi.Srivatsavai@Sun.COM {
498*7738SRishi.Srivatsavai@Sun.COM 	struct interface *p_best = *best;
499*7738SRishi.Srivatsavai@Sun.COM 
500*7738SRishi.Srivatsavai@Sun.COM 	/*
501*7738SRishi.Srivatsavai@Sun.COM 	 * Don't use a duplicate interface since it is unusable for output.
502*7738SRishi.Srivatsavai@Sun.COM 	 */
503*7738SRishi.Srivatsavai@Sun.COM 	if (ifp->int_state & IS_DUP)
504*7738SRishi.Srivatsavai@Sun.COM 		return (_B_FALSE);
505*7738SRishi.Srivatsavai@Sun.COM 
506*7738SRishi.Srivatsavai@Sun.COM 	if (ifp->int_if_flags & IFF_POINTOPOINT) {
507*7738SRishi.Srivatsavai@Sun.COM 		if (ifp->int_dstaddr == addr) {
508*7738SRishi.Srivatsavai@Sun.COM 			*best = NULL;
509*7738SRishi.Srivatsavai@Sun.COM 			return (_B_TRUE);
510*7738SRishi.Srivatsavai@Sun.COM 		}
511*7738SRishi.Srivatsavai@Sun.COM 	} else {
512*7738SRishi.Srivatsavai@Sun.COM 		if (ifp->int_addr == addr) {
513*7738SRishi.Srivatsavai@Sun.COM 			if (IS_PASSIVE_IFP(ifp))
514*7738SRishi.Srivatsavai@Sun.COM 				trace_misc("addr_on_ifp "
515*7738SRishi.Srivatsavai@Sun.COM 				    "returning passive intf %s",
516*7738SRishi.Srivatsavai@Sun.COM 				    ifp->int_name);
517*7738SRishi.Srivatsavai@Sun.COM 			*best = NULL;
518*7738SRishi.Srivatsavai@Sun.COM 			return (_B_TRUE);
519*7738SRishi.Srivatsavai@Sun.COM 		}
520*7738SRishi.Srivatsavai@Sun.COM 
521*7738SRishi.Srivatsavai@Sun.COM 		/* Look for the longest approximate match. */
522*7738SRishi.Srivatsavai@Sun.COM 		if (on_net(addr, ifp->int_net, ifp->int_mask) &&
523*7738SRishi.Srivatsavai@Sun.COM 		    (p_best == NULL ||
524*7738SRishi.Srivatsavai@Sun.COM 		    ifp->int_mask > p_best->int_mask)) {
525*7738SRishi.Srivatsavai@Sun.COM 			*best = ifp;
526*7738SRishi.Srivatsavai@Sun.COM 		}
527*7738SRishi.Srivatsavai@Sun.COM 	}
528*7738SRishi.Srivatsavai@Sun.COM 	return (_B_FALSE);
529*7738SRishi.Srivatsavai@Sun.COM }
5300Sstevel@tonic-gate 
5310Sstevel@tonic-gate /*
5320Sstevel@tonic-gate  * Find an interface which should be receiving packets sent from the
5330Sstevel@tonic-gate  * given address.  Used as a last ditch effort for figuring out which
5340Sstevel@tonic-gate  * interface a packet came in on.  Also used for finding out which
5350Sstevel@tonic-gate  * interface points towards the gateway of static routes learned from
5360Sstevel@tonic-gate  * the kernel.
5370Sstevel@tonic-gate  */
5380Sstevel@tonic-gate struct interface *
iflookup(in_addr_t addr)5390Sstevel@tonic-gate iflookup(in_addr_t addr)
5400Sstevel@tonic-gate {
5410Sstevel@tonic-gate 	struct interface *ifp, *maybe;
5420Sstevel@tonic-gate 
5430Sstevel@tonic-gate 	maybe = NULL;
5440Sstevel@tonic-gate 	for (;;) {
5450Sstevel@tonic-gate 		for (ifp = ifnet; ifp != NULL; ifp = ifp->int_next) {
5460Sstevel@tonic-gate 
547*7738SRishi.Srivatsavai@Sun.COM 			/* Exact match found */
548*7738SRishi.Srivatsavai@Sun.COM 			if (addr_on_ifp(addr, ifp, &maybe))
549*7738SRishi.Srivatsavai@Sun.COM 				return (ifp);
5500Sstevel@tonic-gate 		}
5510Sstevel@tonic-gate 
5520Sstevel@tonic-gate 		/*
5530Sstevel@tonic-gate 		 * If there is no known interface, maybe there is a
5540Sstevel@tonic-gate 		 * new interface.  So just once look for new interfaces.
5550Sstevel@tonic-gate 		 */
5560Sstevel@tonic-gate 		if (maybe == NULL && !IF_RESCAN_DELAY())
5570Sstevel@tonic-gate 			ifscan();
5580Sstevel@tonic-gate 		else
5590Sstevel@tonic-gate 			break;
5600Sstevel@tonic-gate 	}
5610Sstevel@tonic-gate 
5620Sstevel@tonic-gate 	if (maybe != NULL && IS_PASSIVE_IFP(maybe)) {
5630Sstevel@tonic-gate 		trace_misc("iflookup returning passive intf %s",
5640Sstevel@tonic-gate 		    maybe->int_name);
5650Sstevel@tonic-gate 	}
5660Sstevel@tonic-gate 	return (maybe);
5670Sstevel@tonic-gate }
5680Sstevel@tonic-gate 
5690Sstevel@tonic-gate /*
5700Sstevel@tonic-gate  * Find the netmask that would be inferred by RIPv1 listeners
5710Sstevel@tonic-gate  *	on the given interface for a given network.
5720Sstevel@tonic-gate  *	If no interface is specified, look for the best fitting	interface.
5730Sstevel@tonic-gate  */
5740Sstevel@tonic-gate in_addr_t
ripv1_mask_net(in_addr_t addr,const struct interface * ifp)5750Sstevel@tonic-gate ripv1_mask_net(in_addr_t addr,	/* in network byte order */
5760Sstevel@tonic-gate     const struct interface *ifp)	/* as seen on this interface */
5770Sstevel@tonic-gate {
5780Sstevel@tonic-gate 	const struct r1net *r1p;
5790Sstevel@tonic-gate 	in_addr_t mask = 0;
5800Sstevel@tonic-gate 
5810Sstevel@tonic-gate 	if (addr == 0)			/* default always has 0 mask */
5820Sstevel@tonic-gate 		return (mask);
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate 	if (ifp != NULL && ifp->int_ripv1_mask != HOST_MASK) {
5850Sstevel@tonic-gate 		/*
5860Sstevel@tonic-gate 		 * If the target network is that of the associated interface
5870Sstevel@tonic-gate 		 * on which it arrived, then use the netmask of the interface.
5880Sstevel@tonic-gate 		 */
5890Sstevel@tonic-gate 		if (on_net(addr, ifp->int_net, ifp->int_std_mask))
5900Sstevel@tonic-gate 			mask = ifp->int_ripv1_mask;
5910Sstevel@tonic-gate 
5920Sstevel@tonic-gate 	} else {
5930Sstevel@tonic-gate 		/*
5940Sstevel@tonic-gate 		 * Examine all interfaces, and if it the target seems
5950Sstevel@tonic-gate 		 * to have the same network number of an interface, use the
5960Sstevel@tonic-gate 		 * netmask of that interface.  If there is more than one
5970Sstevel@tonic-gate 		 * such interface, prefer the interface with the longest
5980Sstevel@tonic-gate 		 * match.
5990Sstevel@tonic-gate 		 */
6000Sstevel@tonic-gate 		for (ifp = ifnet; ifp != NULL; ifp = ifp->int_next) {
6010Sstevel@tonic-gate 			if (on_net(addr, ifp->int_std_net, ifp->int_std_mask) &&
6020Sstevel@tonic-gate 			    ifp->int_ripv1_mask > mask &&
6030Sstevel@tonic-gate 			    ifp->int_ripv1_mask != HOST_MASK)
6040Sstevel@tonic-gate 				mask = ifp->int_ripv1_mask;
6050Sstevel@tonic-gate 		}
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate 	}
6080Sstevel@tonic-gate 
6090Sstevel@tonic-gate 	if (mask == 0) {
6100Sstevel@tonic-gate 		/*
6110Sstevel@tonic-gate 		 * Check to see if the user has supplied an applicable
6120Sstevel@tonic-gate 		 * netmask as a ripv1_mask option in /etc/gateways.
6130Sstevel@tonic-gate 		 */
6140Sstevel@tonic-gate 		for (r1p = r1nets; r1p != NULL; r1p = r1p->r1net_next) {
6150Sstevel@tonic-gate 			/*
6160Sstevel@tonic-gate 			 * If the address is is on a matching network
6170Sstevel@tonic-gate 			 * and we haven't already found a longer match,
6180Sstevel@tonic-gate 			 * use the matching netmask.
6190Sstevel@tonic-gate 			 */
6200Sstevel@tonic-gate 			if (on_net(addr, r1p->r1net_net, r1p->r1net_match) &&
6210Sstevel@tonic-gate 			    r1p->r1net_mask > mask)
6220Sstevel@tonic-gate 				mask = r1p->r1net_mask;
6230Sstevel@tonic-gate 		}
6240Sstevel@tonic-gate 
6250Sstevel@tonic-gate 		/* Otherwise, make the classic A/B/C guess. */
6260Sstevel@tonic-gate 		if (mask == 0)
6270Sstevel@tonic-gate 			mask = std_mask(addr);
6280Sstevel@tonic-gate 	}
6290Sstevel@tonic-gate 
6300Sstevel@tonic-gate 	return (mask);
6310Sstevel@tonic-gate }
6320Sstevel@tonic-gate 
6330Sstevel@tonic-gate 
6340Sstevel@tonic-gate in_addr_t
ripv1_mask_host(in_addr_t addr,const struct interface * ifp)6350Sstevel@tonic-gate ripv1_mask_host(in_addr_t addr,		/* in network byte order */
6360Sstevel@tonic-gate     const struct interface *ifp)	/* as seen on this interface */
6370Sstevel@tonic-gate {
6380Sstevel@tonic-gate 	in_addr_t mask = ripv1_mask_net(addr, ifp);
6390Sstevel@tonic-gate 
6400Sstevel@tonic-gate 
6410Sstevel@tonic-gate 	/*
6420Sstevel@tonic-gate 	 * If the computed netmask does not mask all of the set bits
6430Sstevel@tonic-gate 	 * in the address, then assume it is a host address
6440Sstevel@tonic-gate 	 */
6450Sstevel@tonic-gate 	if ((ntohl(addr) & ~mask) != 0)
6460Sstevel@tonic-gate 		mask = HOST_MASK;
6470Sstevel@tonic-gate 	return (mask);
6480Sstevel@tonic-gate }
6490Sstevel@tonic-gate 
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate /* See if a IP address looks reasonable as a destination */
6520Sstevel@tonic-gate boolean_t			/* _B_FALSE=bad _B_TRUE=good */
check_dst(in_addr_t addr)6530Sstevel@tonic-gate check_dst(in_addr_t addr)
6540Sstevel@tonic-gate {
6550Sstevel@tonic-gate 	addr = ntohl(addr);
6560Sstevel@tonic-gate 
6570Sstevel@tonic-gate 	if (IN_CLASSA(addr)) {
6580Sstevel@tonic-gate 		if (addr == 0)
6590Sstevel@tonic-gate 			return (_B_TRUE);	/* default */
6600Sstevel@tonic-gate 
6610Sstevel@tonic-gate 		addr >>= IN_CLASSA_NSHIFT;
6620Sstevel@tonic-gate 		return (addr != 0 && addr != IN_LOOPBACKNET);
6630Sstevel@tonic-gate 	}
6640Sstevel@tonic-gate 
6654513Skcpoon 	/* Must not allow destination to be link local address. */
6664513Skcpoon 	if (IN_LINKLOCAL(addr))
6674513Skcpoon 		return (_B_FALSE);
6684513Skcpoon 
6695577Ssangeeta 	if (IN_CLASSB(addr) || IN_CLASSC(addr))
6705577Ssangeeta 		return (_B_TRUE);
6715577Ssangeeta 
6725577Ssangeeta 	if (IN_CLASSD(addr))
6735577Ssangeeta 		return (_B_FALSE);
6745577Ssangeeta 
6755577Ssangeeta 	return (_B_TRUE);
6765577Ssangeeta 
6770Sstevel@tonic-gate }
6780Sstevel@tonic-gate 
6790Sstevel@tonic-gate /*
6800Sstevel@tonic-gate  * Find an existing interface which has the given parameters, but don't
6810Sstevel@tonic-gate  * return the interface with name "name" if "name" is specified.
6820Sstevel@tonic-gate  */
6830Sstevel@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)6840Sstevel@tonic-gate check_dup(const char *name,	/* Don't return this interface */
6850Sstevel@tonic-gate     in_addr_t addr,	/* IP address, so network byte order */
6860Sstevel@tonic-gate     in_addr_t dstaddr,	/* ditto */
6870Sstevel@tonic-gate     in_addr_t mask,	/* mask, so host byte order */
688192Scarlsonj     uint64_t if_flags,	/* set IFF_POINTOPOINT to ignore local int_addr */
6890Sstevel@tonic-gate     boolean_t allowdups)	/* set true to include duplicates */
6900Sstevel@tonic-gate {
6910Sstevel@tonic-gate 	struct interface *best_ifp = NULL;
6920Sstevel@tonic-gate 	struct interface *ifp;
6930Sstevel@tonic-gate 	in_addr_t dstaddr_h = ntohl(dstaddr);
6940Sstevel@tonic-gate 	int best_pref = 0;
6950Sstevel@tonic-gate 	int pref;
6960Sstevel@tonic-gate 
6970Sstevel@tonic-gate 	for (ifp = ifnet; ifp != NULL; ifp = ifp->int_next) {
6980Sstevel@tonic-gate 		/* This interface, not a duplicate. */
6990Sstevel@tonic-gate 		if (name != NULL && strcmp(name, ifp->int_name) == 0)
7000Sstevel@tonic-gate 			continue;
7010Sstevel@tonic-gate 
7020Sstevel@tonic-gate 		/*
7030Sstevel@tonic-gate 		 * Find an interface which isn't already a duplicate to
7040Sstevel@tonic-gate 		 * avoid cyclical duplication.  (i.e. qfe0:1 is a duplicate
7050Sstevel@tonic-gate 		 * of qfe0, and qfe0 is a duplicate of qfe0:1.  That would
7060Sstevel@tonic-gate 		 * be bad)
7070Sstevel@tonic-gate 		 */
7080Sstevel@tonic-gate 		if (!allowdups && (ifp->int_state & IS_DUP))
7090Sstevel@tonic-gate 			continue;
7100Sstevel@tonic-gate 
7110Sstevel@tonic-gate 		if (ifp->int_mask != mask)
7120Sstevel@tonic-gate 			continue;
7130Sstevel@tonic-gate 
7140Sstevel@tonic-gate 		if (!IS_IFF_UP(ifp->int_if_flags))
7150Sstevel@tonic-gate 			continue;
7160Sstevel@tonic-gate 
7170Sstevel@tonic-gate 		/*
7180Sstevel@tonic-gate 		 * The local address can only be shared with a point-to-point
7190Sstevel@tonic-gate 		 * link.
7200Sstevel@tonic-gate 		 */
7210Sstevel@tonic-gate 		if ((ifp->int_addr == addr &&
7220Sstevel@tonic-gate 		    ((if_flags|ifp->int_if_flags) & IFF_POINTOPOINT) == 0) ||
7230Sstevel@tonic-gate 		    on_net(ifp->int_dstaddr, dstaddr_h, mask)) {
7240Sstevel@tonic-gate 			pref = 0;
7250Sstevel@tonic-gate 			if (!(ifp->int_state & IS_ALIAS))
7260Sstevel@tonic-gate 				pref++;
7270Sstevel@tonic-gate 			if (!IS_RIP_OUT_OFF(ifp->int_state))
7280Sstevel@tonic-gate 				pref += 2;
7290Sstevel@tonic-gate 			if (IS_IFF_ROUTING(ifp->int_if_flags))
7300Sstevel@tonic-gate 				pref += 4;
7310Sstevel@tonic-gate 			if (pref > best_pref) {
7320Sstevel@tonic-gate 				best_pref = pref;
7330Sstevel@tonic-gate 				best_ifp = ifp;
7340Sstevel@tonic-gate 			}
7350Sstevel@tonic-gate 		}
7360Sstevel@tonic-gate 	}
7370Sstevel@tonic-gate 	return (best_ifp);
7380Sstevel@tonic-gate }
7390Sstevel@tonic-gate 
7400Sstevel@tonic-gate 
7410Sstevel@tonic-gate /*
7420Sstevel@tonic-gate  * See that a remote gateway is reachable.
7430Sstevel@tonic-gate  *	Note that the answer can change as real interfaces come and go.
7440Sstevel@tonic-gate  */
7450Sstevel@tonic-gate boolean_t			/* _B_FALSE=bad _B_TRUE=good */
check_remote(struct interface * ifp)7460Sstevel@tonic-gate check_remote(struct interface *ifp)
7470Sstevel@tonic-gate {
7480Sstevel@tonic-gate 	struct rt_entry *rt;
7490Sstevel@tonic-gate 
7500Sstevel@tonic-gate 	/* do not worry about other kinds */
7510Sstevel@tonic-gate 	if (!(ifp->int_state & IS_REMOTE))
7524513Skcpoon 		return (_B_TRUE);
7530Sstevel@tonic-gate 
7540Sstevel@tonic-gate 	rt = rtfind(ifp->int_addr);
7550Sstevel@tonic-gate 	if (rt != NULL &&
7560Sstevel@tonic-gate 	    rt->rt_ifp != NULL &&
7574513Skcpoon 	    on_net(ifp->int_addr, rt->rt_ifp->int_net, rt->rt_ifp->int_mask)) {
7580Sstevel@tonic-gate 		return (_B_TRUE);
7594513Skcpoon 	}
7600Sstevel@tonic-gate 
7610Sstevel@tonic-gate 	/*
7620Sstevel@tonic-gate 	 * the gateway cannot be reached directly from one of our
7630Sstevel@tonic-gate 	 * interfaces
7640Sstevel@tonic-gate 	 */
7650Sstevel@tonic-gate 	if (!(ifp->int_state & IS_BROKE)) {
7660Sstevel@tonic-gate 		msglog("unreachable gateway %s in "PATH_GATEWAYS,
7670Sstevel@tonic-gate 		    naddr_ntoa(ifp->int_addr));
7680Sstevel@tonic-gate 		if_bad(ifp, _B_FALSE);
7690Sstevel@tonic-gate 	}
7700Sstevel@tonic-gate 	return (_B_FALSE);
7710Sstevel@tonic-gate }
7720Sstevel@tonic-gate 
7730Sstevel@tonic-gate /* Delete an interface. */
7740Sstevel@tonic-gate static void
ifdel(struct interface * ifp)7750Sstevel@tonic-gate ifdel(struct interface *ifp)
7760Sstevel@tonic-gate {
7770Sstevel@tonic-gate 	struct rewire_data wire;
7780Sstevel@tonic-gate 	boolean_t resurrected;
7790Sstevel@tonic-gate 	struct physical_interface *phyi;
7800Sstevel@tonic-gate 
7810Sstevel@tonic-gate 	trace_if("Del", ifp);
7820Sstevel@tonic-gate 
7830Sstevel@tonic-gate 	ifp->int_state |= IS_BROKE;
7840Sstevel@tonic-gate 
7850Sstevel@tonic-gate 	/* unlink the interface */
7860Sstevel@tonic-gate 	link_out(ifp, offsetof(struct interface, int_link));
7870Sstevel@tonic-gate 	hash_unlink(&ahash_tbl, ifp);
7880Sstevel@tonic-gate 	hash_unlink(&nhash_tbl, ifp);
7890Sstevel@tonic-gate 	if (ifp->int_if_flags & IFF_BROADCAST)
7900Sstevel@tonic-gate 		hash_unlink(&bhash_tbl, ifp);
7910Sstevel@tonic-gate 
7920Sstevel@tonic-gate 	/* Remove from list of interfaces with this ifIndex */
7930Sstevel@tonic-gate 	if ((phyi = ifp->int_phys) != NULL) {
7940Sstevel@tonic-gate 		link_out(ifp, offsetof(struct interface, int_ilist));
7950Sstevel@tonic-gate 		if (phyi->phyi_interface == NULL) {
7960Sstevel@tonic-gate 			hash_unlink(&ihash_tbl, phyi);
7970Sstevel@tonic-gate 			free(phyi);
7980Sstevel@tonic-gate 		}
7990Sstevel@tonic-gate 	}
8000Sstevel@tonic-gate 
8010Sstevel@tonic-gate 	/*
8020Sstevel@tonic-gate 	 * If this is a lead interface, then check first for
8030Sstevel@tonic-gate 	 * duplicates of this interface with an eye towards promoting
8040Sstevel@tonic-gate 	 * one of them.
8050Sstevel@tonic-gate 	 */
8060Sstevel@tonic-gate 	resurrected = _B_FALSE;
8070Sstevel@tonic-gate 	if (!(ifp->int_state & IS_DUP) &&
8080Sstevel@tonic-gate 	    (wire.if_new = check_dup(ifp->int_name, ifp->int_addr,
8094513Skcpoon 	    ifp->int_dstaddr, ifp->int_mask, ifp->int_if_flags,
8104513Skcpoon 	    _B_TRUE)) != NULL &&
8110Sstevel@tonic-gate 	    !IS_IFF_QUIET(wire.if_new->int_if_flags)) {
8120Sstevel@tonic-gate 
8130Sstevel@tonic-gate 		trace_act("promoting duplicate %s in place of %s",
8140Sstevel@tonic-gate 		    wire.if_new->int_name, ifp->int_name);
8150Sstevel@tonic-gate 
8160Sstevel@tonic-gate 		/* Rewire routes with the replacement interface */
8170Sstevel@tonic-gate 		wire.if_old = ifp;
8180Sstevel@tonic-gate 		wire.metric_delta = wire.if_new->int_metric - ifp->int_metric;
8190Sstevel@tonic-gate 		(void) rn_walktree(rhead, walk_rewire, &wire);
8200Sstevel@tonic-gate 		kern_rewire_ifp(wire.if_old, wire.if_new);
8210Sstevel@tonic-gate 		if_rewire_rdisc(wire.if_old, wire.if_new);
8220Sstevel@tonic-gate 
8230Sstevel@tonic-gate 		/* Mark the replacement as being no longer a duplicate */
8240Sstevel@tonic-gate 		wire.if_new->int_state &= ~IS_DUP;
8250Sstevel@tonic-gate 		tot_interfaces++;
8260Sstevel@tonic-gate 		if (!IS_RIP_OFF(wire.if_new->int_state))
8270Sstevel@tonic-gate 			rip_interfaces++;
8280Sstevel@tonic-gate 		if (!IS_RIP_OUT_OFF(wire.if_new->int_state))
8290Sstevel@tonic-gate 			ripout_interfaces++;
8300Sstevel@tonic-gate 		if (IS_IFF_ROUTING(wire.if_new->int_if_flags))
8310Sstevel@tonic-gate 			fwd_interfaces++;
8320Sstevel@tonic-gate 
8330Sstevel@tonic-gate 		set_rdisc_mg(wire.if_new, 1);
8340Sstevel@tonic-gate 		rip_mcast_on(wire.if_new);
8350Sstevel@tonic-gate 
8360Sstevel@tonic-gate 		/* We came out ok; no need to clobber routes over this. */
8370Sstevel@tonic-gate 		resurrected = _B_TRUE;
8380Sstevel@tonic-gate 	}
8390Sstevel@tonic-gate 
8400Sstevel@tonic-gate 	rip_mcast_off(ifp);
8410Sstevel@tonic-gate 	if (rip_sock_interface == ifp)
8420Sstevel@tonic-gate 		rip_sock_interface = NULL;
8430Sstevel@tonic-gate 
8440Sstevel@tonic-gate 	set_rdisc_mg(ifp, 0);
8450Sstevel@tonic-gate 
8460Sstevel@tonic-gate 	/*
8470Sstevel@tonic-gate 	 * Note that duplicates are not counted in the total number of
8480Sstevel@tonic-gate 	 * interfaces.
8490Sstevel@tonic-gate 	 */
8500Sstevel@tonic-gate 	if (!(ifp->int_state & IS_DUP) && !IS_IFF_QUIET(ifp->int_if_flags)) {
8510Sstevel@tonic-gate 		tot_interfaces--;
8520Sstevel@tonic-gate 		if (!IS_RIP_OFF(ifp->int_state))
8530Sstevel@tonic-gate 			rip_interfaces--;
8540Sstevel@tonic-gate 		if (!IS_RIP_OUT_OFF(ifp->int_state))
8550Sstevel@tonic-gate 			ripout_interfaces--;
8560Sstevel@tonic-gate 		if (IS_IFF_ROUTING(ifp->int_if_flags))
8570Sstevel@tonic-gate 			fwd_interfaces--;
8580Sstevel@tonic-gate 	}
8590Sstevel@tonic-gate 
8600Sstevel@tonic-gate 	if (!resurrected) {
8610Sstevel@tonic-gate 		/*
8620Sstevel@tonic-gate 		 * Zap all routes associated with this interface.
8630Sstevel@tonic-gate 		 * Assume routes just using gateways beyond this interface
8640Sstevel@tonic-gate 		 * will timeout naturally, and have probably already died.
8650Sstevel@tonic-gate 		 */
8660Sstevel@tonic-gate 		(void) rn_walktree(rhead, walk_bad, ifp);
8670Sstevel@tonic-gate 		kern_flush_ifp(ifp);
8680Sstevel@tonic-gate 
8690Sstevel@tonic-gate 		if_bad_rdisc(ifp);
8700Sstevel@tonic-gate 	}
8710Sstevel@tonic-gate 
8720Sstevel@tonic-gate 	free(ifp);
8730Sstevel@tonic-gate }
8740Sstevel@tonic-gate 
8750Sstevel@tonic-gate 
8760Sstevel@tonic-gate /* Mark an interface ill. */
8770Sstevel@tonic-gate void
if_sick(struct interface * ifp,boolean_t recurse)8780Sstevel@tonic-gate if_sick(struct interface *ifp, boolean_t recurse)
8790Sstevel@tonic-gate {
8800Sstevel@tonic-gate 	struct interface *ifp1;
8810Sstevel@tonic-gate 
8820Sstevel@tonic-gate 	if (0 == (ifp->int_state & (IS_SICK | IS_BROKE))) {
8830Sstevel@tonic-gate 		ifp->int_state |= IS_SICK;
8840Sstevel@tonic-gate 		ifp->int_act_time = NEVER;
8850Sstevel@tonic-gate 		trace_if("Chg", ifp);
8860Sstevel@tonic-gate 
8870Sstevel@tonic-gate 		LIM_SEC(ifscan_timer, now.tv_sec+CHECK_BAD_INTERVAL);
8880Sstevel@tonic-gate 		if (recurse && ifp->int_phys != NULL) {
8890Sstevel@tonic-gate 			/* If an interface is sick, so are its aliases. */
8900Sstevel@tonic-gate 			for (ifp1 = ifp->int_phys->phyi_interface;
8910Sstevel@tonic-gate 			    ifp1 != NULL; ifp1 = ifp1->int_ilist.hl_next) {
8920Sstevel@tonic-gate 				if (ifp1 != ifp)
8930Sstevel@tonic-gate 					if_sick(ifp1, _B_FALSE);
8940Sstevel@tonic-gate 			}
8950Sstevel@tonic-gate 		}
8960Sstevel@tonic-gate 	}
8970Sstevel@tonic-gate }
8980Sstevel@tonic-gate 
8990Sstevel@tonic-gate 
9000Sstevel@tonic-gate /* Mark an interface dead. */
9010Sstevel@tonic-gate static void
if_bad(struct interface * ifp,boolean_t recurse)9020Sstevel@tonic-gate if_bad(struct interface *ifp, boolean_t recurse)
9030Sstevel@tonic-gate {
9040Sstevel@tonic-gate 	struct interface *ifp1;
9050Sstevel@tonic-gate 	struct rewire_data wire;
9060Sstevel@tonic-gate 
9070Sstevel@tonic-gate 	if (ifp->int_state & IS_BROKE)
9080Sstevel@tonic-gate 		return;
9090Sstevel@tonic-gate 
9100Sstevel@tonic-gate 	LIM_SEC(ifscan_timer, now.tv_sec+CHECK_BAD_INTERVAL);
9110Sstevel@tonic-gate 
9120Sstevel@tonic-gate 	ifp->int_state |= (IS_BROKE | IS_SICK);
9130Sstevel@tonic-gate 	ifp->int_act_time = NEVER;
9140Sstevel@tonic-gate 	ifp->int_query_time = NEVER;
9150Sstevel@tonic-gate 	/* Note: don't reset the stats timestamp here */
9160Sstevel@tonic-gate 
9170Sstevel@tonic-gate 	trace_if("Chg", ifp);
9180Sstevel@tonic-gate 
9190Sstevel@tonic-gate 	if (recurse && ifp->int_phys != NULL) {
9200Sstevel@tonic-gate 		/* If an interface is bad, so are its aliases. */
9210Sstevel@tonic-gate 		for (ifp1 = ifp->int_phys->phyi_interface;
9220Sstevel@tonic-gate 		    ifp1 != NULL; ifp1 = ifp1->int_ilist.hl_next) {
9230Sstevel@tonic-gate 			if (ifp1 != ifp)
9240Sstevel@tonic-gate 				if_bad(ifp1, _B_FALSE);
9250Sstevel@tonic-gate 		}
9260Sstevel@tonic-gate 	}
9270Sstevel@tonic-gate 
9280Sstevel@tonic-gate 	/* If we can find a replacement, then pick it up. */
9290Sstevel@tonic-gate 	if (!(ifp->int_state & IS_DUP) &&
9300Sstevel@tonic-gate 	    (wire.if_new = check_dup(ifp->int_name, ifp->int_addr,
9314513Skcpoon 	    ifp->int_dstaddr, ifp->int_mask, ifp->int_if_flags,
9324513Skcpoon 	    _B_TRUE)) != NULL &&
9330Sstevel@tonic-gate 	    !IS_IFF_QUIET(wire.if_new->int_if_flags)) {
9340Sstevel@tonic-gate 		trace_act("promoting duplicate %s in place of %s",
9350Sstevel@tonic-gate 		    wire.if_new->int_name, ifp->int_name);
9360Sstevel@tonic-gate 		wire.if_old = ifp;
9370Sstevel@tonic-gate 		wire.metric_delta = wire.if_new->int_metric - ifp->int_metric;
9380Sstevel@tonic-gate 		(void) rn_walktree(rhead, walk_rewire, &wire);
9390Sstevel@tonic-gate 		if_rewire_rdisc(wire.if_old, wire.if_new);
9400Sstevel@tonic-gate 
9410Sstevel@tonic-gate 		/* The broken guy becomes the duplicate */
9420Sstevel@tonic-gate 		wire.if_new->int_state &= ~IS_DUP;
9430Sstevel@tonic-gate 		set_rdisc_mg(ifp, 0);
9440Sstevel@tonic-gate 		rip_mcast_off(ifp);
9450Sstevel@tonic-gate 		ifp->int_state |= IS_DUP;
9460Sstevel@tonic-gate 
9470Sstevel@tonic-gate 		/* join the mcast groups for the replacement */
9480Sstevel@tonic-gate 		set_rdisc_mg(wire.if_new, 1);
9490Sstevel@tonic-gate 		rip_mcast_on(wire.if_new);
9500Sstevel@tonic-gate 
9510Sstevel@tonic-gate 		if (rip_sock_interface == ifp)
9520Sstevel@tonic-gate 			rip_sock_interface = NULL;
9530Sstevel@tonic-gate 	} else {
9540Sstevel@tonic-gate 		(void) rn_walktree(rhead, walk_bad, ifp);
9550Sstevel@tonic-gate 		if_bad_rdisc(ifp);
9560Sstevel@tonic-gate 	}
9570Sstevel@tonic-gate }
9580Sstevel@tonic-gate 
9590Sstevel@tonic-gate 
9600Sstevel@tonic-gate /* Mark an interface alive */
9610Sstevel@tonic-gate void
if_ok(struct interface * ifp,const char * type,boolean_t recurse)9620Sstevel@tonic-gate if_ok(struct interface *ifp, const char *type, boolean_t recurse)
9630Sstevel@tonic-gate {
9640Sstevel@tonic-gate 	struct interface *ifp1;
9650Sstevel@tonic-gate 	boolean_t wasbroken = _B_FALSE;
9660Sstevel@tonic-gate 
9670Sstevel@tonic-gate 	if (ifp->int_state & IS_BROKE) {
9680Sstevel@tonic-gate 		writelog(LOG_WARNING, "%sinterface %s to %s restored",
9690Sstevel@tonic-gate 		    type, ifp->int_name, naddr_ntoa(ifp->int_dstaddr));
9700Sstevel@tonic-gate 		ifp->int_state &= ~(IS_BROKE | IS_SICK);
9710Sstevel@tonic-gate 		wasbroken = _B_TRUE;
9720Sstevel@tonic-gate 	} else if (ifp->int_state & IS_SICK) {
9730Sstevel@tonic-gate 		trace_act("%sinterface %s to %s working better",
9740Sstevel@tonic-gate 		    type, ifp->int_name, naddr_ntoa(ifp->int_dstaddr));
9750Sstevel@tonic-gate 		ifp->int_state &= ~IS_SICK;
9760Sstevel@tonic-gate 	}
9770Sstevel@tonic-gate 
9780Sstevel@tonic-gate 	if (recurse && ifp->int_phys != NULL && IS_IFF_UP(ifp->int_if_flags)) {
9790Sstevel@tonic-gate 		ifp->int_phys->phyi_data.ts = 0;
9800Sstevel@tonic-gate 
9810Sstevel@tonic-gate 		/* Also mark all aliases of this interface as ok */
9820Sstevel@tonic-gate 		for (ifp1 = ifp->int_phys->phyi_interface;
9830Sstevel@tonic-gate 		    ifp1 != NULL; ifp1 = ifp1->int_ilist.hl_next) {
9840Sstevel@tonic-gate 			if (ifp1 != ifp)
9850Sstevel@tonic-gate 				if_ok(ifp1, type, _B_FALSE);
9860Sstevel@tonic-gate 		}
9870Sstevel@tonic-gate 	}
9880Sstevel@tonic-gate 
9890Sstevel@tonic-gate 	if (wasbroken) {
9900Sstevel@tonic-gate 		if (!(ifp->int_state & IS_DUP))
9910Sstevel@tonic-gate 			if_ok_rdisc(ifp);
9920Sstevel@tonic-gate 
9930Sstevel@tonic-gate 		if (ifp->int_state & IS_REMOTE)
9940Sstevel@tonic-gate 			(void) addrouteforif(ifp);
9950Sstevel@tonic-gate 	}
9960Sstevel@tonic-gate }
9970Sstevel@tonic-gate 
9980Sstevel@tonic-gate boolean_t
remote_address_ok(struct interface * ifp,in_addr_t addr)9990Sstevel@tonic-gate remote_address_ok(struct interface *ifp, in_addr_t addr)
10000Sstevel@tonic-gate {
10010Sstevel@tonic-gate 	if (ifp->int_if_flags & IFF_POINTOPOINT) {
10020Sstevel@tonic-gate 		if (addr == ifp->int_dstaddr)
10030Sstevel@tonic-gate 			return (_B_TRUE);
10040Sstevel@tonic-gate 	} else if (on_net(addr, ifp->int_net, ifp->int_mask)) {
10050Sstevel@tonic-gate 		return (_B_TRUE);
10060Sstevel@tonic-gate 	}
10070Sstevel@tonic-gate 	return (_B_FALSE);
10080Sstevel@tonic-gate }
10090Sstevel@tonic-gate 
10100Sstevel@tonic-gate /*
10110Sstevel@tonic-gate  * Find the network interfaces which have configured themselves.
10120Sstevel@tonic-gate  *	This must be done regularly, if only for extra addresses
10130Sstevel@tonic-gate  *	that come and go on interfaces.
10140Sstevel@tonic-gate  */
10150Sstevel@tonic-gate void
ifscan(void)10160Sstevel@tonic-gate ifscan(void)
10170Sstevel@tonic-gate {
10180Sstevel@tonic-gate 	uint_t complaints = 0;
10190Sstevel@tonic-gate 	static uint_t prev_complaints = 0;
10200Sstevel@tonic-gate #define	COMP_BADADDR	0x001
10210Sstevel@tonic-gate #define	COMP_NODST	0x002
10220Sstevel@tonic-gate #define	COMP_NOBADDR	0x004
10230Sstevel@tonic-gate #define	COMP_NOMASK	0x008
10240Sstevel@tonic-gate #define	COMP_BAD_METRIC	0x010
10250Sstevel@tonic-gate #define	COMP_NETMASK	0x020
10260Sstevel@tonic-gate #define	COMP_NO_INDEX	0x040
10270Sstevel@tonic-gate #define	COMP_BAD_FLAGS	0x080
10280Sstevel@tonic-gate #define	COMP_NO_KSTATS	0x100
10290Sstevel@tonic-gate #define	COMP_IPFORWARD	0x200
10300Sstevel@tonic-gate 
10310Sstevel@tonic-gate 	struct interface ifs, *ifp, *ifp1;
10320Sstevel@tonic-gate 	struct rt_entry *rt;
10330Sstevel@tonic-gate 	size_t needed;
10340Sstevel@tonic-gate 	static size_t lastneeded = 0;
10350Sstevel@tonic-gate 	char *buf;
10360Sstevel@tonic-gate 	static char *lastbuf = NULL;
10370Sstevel@tonic-gate 	int32_t in, ierr, out, oerr;
10380Sstevel@tonic-gate 	struct intnet *intnetp;
10390Sstevel@tonic-gate 	int sock;
10400Sstevel@tonic-gate 	struct lifnum lifn;
10410Sstevel@tonic-gate 	struct lifconf lifc;
10420Sstevel@tonic-gate 	struct lifreq *lifrp, *lifrp_lim;
10430Sstevel@tonic-gate 	struct sockaddr_in *sinp;
10440Sstevel@tonic-gate 	in_addr_t haddr;
10450Sstevel@tonic-gate 	static in_addr_t myaddr = 0;
10460Sstevel@tonic-gate 	uint32_t ifindex;
10470Sstevel@tonic-gate 	struct phyi_data newstats;
10480Sstevel@tonic-gate 	struct physical_interface *phyi;
10490Sstevel@tonic-gate 
10500Sstevel@tonic-gate 	last_ifscan = now;
10510Sstevel@tonic-gate 	ifscan_timer.tv_sec = now.tv_sec +
10520Sstevel@tonic-gate 	    (supplier || tot_interfaces != 1 ?
10534513Skcpoon 	    CHECK_ACT_INTERVAL : CHECK_QUIET_INTERVAL);
10540Sstevel@tonic-gate 
10550Sstevel@tonic-gate 	/* mark all interfaces so we can get rid of those that disappear */
10560Sstevel@tonic-gate 	for (ifp = ifnet; ifp != NULL; ifp = ifp->int_next)
10570Sstevel@tonic-gate 		ifp->int_state &= ~IS_CHECKED;
10580Sstevel@tonic-gate 
10590Sstevel@tonic-gate 	/* Fetch the size of the current interface list */
10600Sstevel@tonic-gate 	if ((sock = socket(PF_INET, SOCK_DGRAM, 0)) == -1)
10610Sstevel@tonic-gate 		BADERR(_B_TRUE, "ifscan: socket(SOCK_DGRAM)");
10620Sstevel@tonic-gate 	lifn.lifn_family = AF_INET;	/* Only count IPv4 interfaces */
10630Sstevel@tonic-gate 	/*
10640Sstevel@tonic-gate 	 * Include IFF_NOXMIT interfaces.  Such interfaces are exluded
10650Sstevel@tonic-gate 	 * from protocol operations, but their inclusion in the
10660Sstevel@tonic-gate 	 * internal table enables us to know when packets arrive on
10670Sstevel@tonic-gate 	 * such interfaces.
10680Sstevel@tonic-gate 	 */
10690Sstevel@tonic-gate 	lifn.lifn_flags = LIFC_NOXMIT;
10700Sstevel@tonic-gate calculate_lifc_len:
10710Sstevel@tonic-gate 	if (ioctl(sock, SIOCGLIFNUM, &lifn) == -1) {
10720Sstevel@tonic-gate 		BADERR(_B_TRUE, "ifscan: ioctl(SIOCGLIFNUM)");
10730Sstevel@tonic-gate 	}
10740Sstevel@tonic-gate 
10750Sstevel@tonic-gate 	/*
10760Sstevel@tonic-gate 	 * When calculating the buffer size needed, add a small number
10770Sstevel@tonic-gate 	 * of interfaces to those we counted.  We do this to capture
10780Sstevel@tonic-gate 	 * the interface status of potential interfaces which may have
10790Sstevel@tonic-gate 	 * been plumbed between the SIOCGLIFNUM and the SIOCGLIFCONF.
10800Sstevel@tonic-gate 	 * Try to reuse the buffer we already have to avoid heap
10810Sstevel@tonic-gate 	 * thrash.
10820Sstevel@tonic-gate 	 */
10830Sstevel@tonic-gate 	needed = (lifn.lifn_count + 4) * sizeof (struct lifreq);
10840Sstevel@tonic-gate 	if (needed > lastneeded || needed < lastneeded/2) {
10850Sstevel@tonic-gate 		if (lastbuf != NULL)
10860Sstevel@tonic-gate 			free(lastbuf);
10870Sstevel@tonic-gate 		if ((buf = malloc(needed)) == NULL) {
10880Sstevel@tonic-gate 			lastbuf = NULL;
10890Sstevel@tonic-gate 			msglog("ifscan: malloc: %s", rip_strerror(errno));
10900Sstevel@tonic-gate 			return;
10910Sstevel@tonic-gate 		}
10920Sstevel@tonic-gate 	} else {
10930Sstevel@tonic-gate 		buf = lastbuf;
10940Sstevel@tonic-gate 	}
10950Sstevel@tonic-gate 	lastbuf = buf;
10960Sstevel@tonic-gate 	lastneeded = needed;
10970Sstevel@tonic-gate 
10980Sstevel@tonic-gate 	/* Get the list */
10990Sstevel@tonic-gate 	lifc.lifc_family = AF_INET;	/* We only need IPv4 interfaces */
11000Sstevel@tonic-gate 	lifc.lifc_flags = LIFC_NOXMIT;
11010Sstevel@tonic-gate 	lifc.lifc_len = needed;
11020Sstevel@tonic-gate 	lifc.lifc_buf = buf;
11030Sstevel@tonic-gate 	if (ioctl(sock, SIOCGLIFCONF, &lifc) == -1) {
11040Sstevel@tonic-gate 		/*
11050Sstevel@tonic-gate 		 * IP returns EINVAL if the lifc_len we passed in is
11060Sstevel@tonic-gate 		 * too small.  If that's the case, we need to go back
11070Sstevel@tonic-gate 		 * and recalculate it.
11080Sstevel@tonic-gate 		 */
11090Sstevel@tonic-gate 		if (errno == EINVAL)
11100Sstevel@tonic-gate 			goto calculate_lifc_len;
11110Sstevel@tonic-gate 		BADERR(_B_TRUE, "ifscan: ioctl(SIOCGLIFCONF)");
11120Sstevel@tonic-gate 	}
11130Sstevel@tonic-gate 
11140Sstevel@tonic-gate 	/*
11150Sstevel@tonic-gate 	 * If the returned lifc_len is within one lifreq of the
11160Sstevel@tonic-gate 	 * requested ammount, we may have used a buffer which
11170Sstevel@tonic-gate 	 * was too small to hold all of the interfaces.  In that
11180Sstevel@tonic-gate 	 * case go back and recalculate needed.
11190Sstevel@tonic-gate 	 */
11200Sstevel@tonic-gate 	if (lifc.lifc_len >= needed - sizeof (struct lifreq))
11210Sstevel@tonic-gate 		goto calculate_lifc_len;
11220Sstevel@tonic-gate 
11230Sstevel@tonic-gate 	lifrp = lifc.lifc_req;
11240Sstevel@tonic-gate 	lifrp_lim = lifrp + lifc.lifc_len / sizeof (*lifrp);
11250Sstevel@tonic-gate 	for (; lifrp < lifrp_lim; lifrp++) {
11260Sstevel@tonic-gate 
11270Sstevel@tonic-gate 		(void) memset(&ifs, 0, sizeof (ifs));
11280Sstevel@tonic-gate 
11290Sstevel@tonic-gate 		(void) strlcpy(ifs.int_name, lifrp->lifr_name,
11300Sstevel@tonic-gate 		    sizeof (ifs.int_name));
11310Sstevel@tonic-gate 
11320Sstevel@tonic-gate 		/* SIOCGLIFCONF fills in the lifr_addr of each lifreq */
11330Sstevel@tonic-gate 		ifs.int_addr = ((struct sockaddr_in *)&lifrp->lifr_addr)->
11340Sstevel@tonic-gate 		    sin_addr.s_addr;
11350Sstevel@tonic-gate 
11360Sstevel@tonic-gate 		if (ioctl(sock, SIOCGLIFFLAGS, lifrp) == -1) {
11370Sstevel@tonic-gate 			if (!(prev_complaints & COMP_BAD_FLAGS))
11380Sstevel@tonic-gate 				writelog(LOG_NOTICE,
11390Sstevel@tonic-gate 				    "unable to get interface flags for %s: %s",
11400Sstevel@tonic-gate 				    ifs.int_name, rip_strerror(errno));
11410Sstevel@tonic-gate 			complaints |= COMP_BAD_FLAGS;
11420Sstevel@tonic-gate 			ifs.int_if_flags = 0;
11430Sstevel@tonic-gate 		} else {
11440Sstevel@tonic-gate 			ifs.int_if_flags = lifrp->lifr_flags;
11450Sstevel@tonic-gate 		}
11460Sstevel@tonic-gate 
11475577Ssangeeta 		if (IN_CLASSD(ntohl(ifs.int_addr)) ||
11480Sstevel@tonic-gate 		    (ntohl(ifs.int_addr) & IN_CLASSA_NET) == 0) {
11490Sstevel@tonic-gate 			if (IS_IFF_UP(ifs.int_if_flags)) {
11500Sstevel@tonic-gate 				if (!(prev_complaints & COMP_BADADDR))
11510Sstevel@tonic-gate 					writelog(LOG_NOTICE,
11520Sstevel@tonic-gate 					    "%s has a bad address %s",
11530Sstevel@tonic-gate 					    ifs.int_name,
11540Sstevel@tonic-gate 					    naddr_ntoa(ifs.int_addr));
11550Sstevel@tonic-gate 				complaints |= COMP_BADADDR;
11560Sstevel@tonic-gate 			}
11570Sstevel@tonic-gate 			continue;
11580Sstevel@tonic-gate 		}
11590Sstevel@tonic-gate 
11604513Skcpoon 		/* Ignore interface with IPv4 link local address. */
11614513Skcpoon 		if (IN_LINKLOCAL(ntohl(ifs.int_addr)))
11624513Skcpoon 			continue;
11634513Skcpoon 
11640Sstevel@tonic-gate 		/* Get the interface index. */
11650Sstevel@tonic-gate 		if (ioctl(sock, SIOCGLIFINDEX, lifrp) == -1) {
11660Sstevel@tonic-gate 			ifindex = 0;
11670Sstevel@tonic-gate 			ifs.int_if_flags &= ~IFF_UP;
11680Sstevel@tonic-gate 			if (!(prev_complaints & COMP_NO_INDEX))
11690Sstevel@tonic-gate 				writelog(LOG_NOTICE, "%s has no ifIndex: %s",
11700Sstevel@tonic-gate 				    ifs.int_name, rip_strerror(errno));
11710Sstevel@tonic-gate 			complaints |= COMP_NO_INDEX;
11720Sstevel@tonic-gate 		} else {
11730Sstevel@tonic-gate 			ifindex = lifrp->lifr_index;
11740Sstevel@tonic-gate 		}
11750Sstevel@tonic-gate 
11760Sstevel@tonic-gate 		/*
11770Sstevel@tonic-gate 		 * Get the destination address for point-to-point
11780Sstevel@tonic-gate 		 * interfaces.
11790Sstevel@tonic-gate 		 */
11800Sstevel@tonic-gate 		if (ifs.int_if_flags & IFF_POINTOPOINT) {
11810Sstevel@tonic-gate 			sinp = (struct sockaddr_in *)&lifrp->lifr_dstaddr;
11820Sstevel@tonic-gate 			if (ioctl(sock, SIOCGLIFDSTADDR, lifrp) == -1) {
11830Sstevel@tonic-gate 				if (IS_IFF_UP(ifs.int_if_flags)) {
11840Sstevel@tonic-gate 					if (!(prev_complaints & COMP_NODST))
11850Sstevel@tonic-gate 						writelog(LOG_NOTICE,
11860Sstevel@tonic-gate 						    "%s has no destination "
11870Sstevel@tonic-gate 						    "address : %s",
11880Sstevel@tonic-gate 						    ifs.int_name,
11890Sstevel@tonic-gate 						    rip_strerror(errno));
11900Sstevel@tonic-gate 					complaints |= COMP_NODST;
11910Sstevel@tonic-gate 				}
11920Sstevel@tonic-gate 				continue;
11930Sstevel@tonic-gate 			}
11940Sstevel@tonic-gate 			ifs.int_net = ntohl(sinp->sin_addr.s_addr);
11955577Ssangeeta 			if (IN_CLASSD(ntohl(ifs.int_net)) ||
11965580Ssangeeta 			    (ifs.int_net != 0 &&
11970Sstevel@tonic-gate 			    (ifs.int_net & IN_CLASSA_NET) == 0)) {
11980Sstevel@tonic-gate 				if (IS_IFF_UP(ifs.int_if_flags)) {
11990Sstevel@tonic-gate 					if (!(prev_complaints & COMP_NODST))
12000Sstevel@tonic-gate 						writelog(LOG_NOTICE,
12010Sstevel@tonic-gate 						    "%s has a bad "
12020Sstevel@tonic-gate 						    "destination address %s",
12030Sstevel@tonic-gate 						    ifs.int_name,
12040Sstevel@tonic-gate 						    naddr_ntoa(ifs.int_net));
12050Sstevel@tonic-gate 					complaints |= COMP_NODST;
12060Sstevel@tonic-gate 				}
12070Sstevel@tonic-gate 				continue;
12080Sstevel@tonic-gate 			}
12090Sstevel@tonic-gate 			ifs.int_dstaddr = sinp->sin_addr.s_addr;
12100Sstevel@tonic-gate 		}
12110Sstevel@tonic-gate 
12120Sstevel@tonic-gate 		/* Get the subnet mask */
12130Sstevel@tonic-gate 		sinp = (struct sockaddr_in *)&lifrp->lifr_addr;
12140Sstevel@tonic-gate 		if (ioctl(sock, SIOCGLIFNETMASK, lifrp) == -1) {
12150Sstevel@tonic-gate 			if (IS_IFF_UP(ifs.int_if_flags)) {
12160Sstevel@tonic-gate 				if (!(prev_complaints & COMP_NOMASK))
12170Sstevel@tonic-gate 					writelog(LOG_NOTICE,
12180Sstevel@tonic-gate 					    "%s has no netmask: %s",
12190Sstevel@tonic-gate 					    ifs.int_name, rip_strerror(errno));
12200Sstevel@tonic-gate 				complaints |= COMP_NOMASK;
12210Sstevel@tonic-gate 			}
12220Sstevel@tonic-gate 			continue;
12230Sstevel@tonic-gate 		}
12240Sstevel@tonic-gate 		if (sinp->sin_addr.s_addr == INADDR_ANY) {
12250Sstevel@tonic-gate 			if (!(ifs.int_if_flags &
12260Sstevel@tonic-gate 			    (IFF_POINTOPOINT|IFF_LOOPBACK))) {
12270Sstevel@tonic-gate 				if (IS_IFF_UP(ifs.int_if_flags)) {
12280Sstevel@tonic-gate 					if (!(prev_complaints & COMP_NOMASK))
12290Sstevel@tonic-gate 						writelog(LOG_NOTICE,
12300Sstevel@tonic-gate 						    "%s has all-zero netmask",
12310Sstevel@tonic-gate 						    ifs.int_name);
12320Sstevel@tonic-gate 					complaints |= COMP_NOMASK;
12330Sstevel@tonic-gate 				}
12340Sstevel@tonic-gate 				continue;
12350Sstevel@tonic-gate 			}
12360Sstevel@tonic-gate 			ifs.int_mask = IP_HOST_MASK;
12370Sstevel@tonic-gate 		} else {
12380Sstevel@tonic-gate 			ifs.int_mask = ntohl(sinp->sin_addr.s_addr);
12390Sstevel@tonic-gate 		}
12400Sstevel@tonic-gate 
12410Sstevel@tonic-gate 		/*
12420Sstevel@tonic-gate 		 * Get the broadcast address on broadcast capable
12430Sstevel@tonic-gate 		 * interfaces.
12440Sstevel@tonic-gate 		 */
12450Sstevel@tonic-gate 		if (ifs.int_if_flags & IFF_BROADCAST) {
12460Sstevel@tonic-gate 			if (ioctl(sock, SIOCGLIFBRDADDR, lifrp) == -1) {
12470Sstevel@tonic-gate 				if (IS_IFF_UP(ifs.int_if_flags)) {
12480Sstevel@tonic-gate 					if (!(prev_complaints & COMP_NOBADDR))
12490Sstevel@tonic-gate 						writelog(LOG_NOTICE,
12500Sstevel@tonic-gate 						    "%s has no broadcast "
12510Sstevel@tonic-gate 						    "address: %s",
12520Sstevel@tonic-gate 						    ifs.int_name,
12530Sstevel@tonic-gate 						    rip_strerror(errno));
12540Sstevel@tonic-gate 					complaints |= COMP_NOBADDR;
12550Sstevel@tonic-gate 				}
12560Sstevel@tonic-gate 				continue;
12570Sstevel@tonic-gate 			}
12580Sstevel@tonic-gate 			haddr = ntohl(sinp->sin_addr.s_addr);
12595577Ssangeeta 			if (IN_CLASSD(haddr) ||
12605580Ssangeeta 			    (haddr & IN_CLASSA_NET) == 0) {
12610Sstevel@tonic-gate 				if (IS_IFF_UP(ifs.int_if_flags)) {
12620Sstevel@tonic-gate 					if (!(prev_complaints & COMP_NOBADDR))
12630Sstevel@tonic-gate 						writelog(LOG_NOTICE,
12640Sstevel@tonic-gate 						    "%s has a bad broadcast "
12650Sstevel@tonic-gate 						    "address %s",
12660Sstevel@tonic-gate 						    ifs.int_name,
12670Sstevel@tonic-gate 						    naddr_ntoa(haddr));
12680Sstevel@tonic-gate 					complaints |= COMP_NOBADDR;
12690Sstevel@tonic-gate 				}
12700Sstevel@tonic-gate 				continue;
12710Sstevel@tonic-gate 			}
12720Sstevel@tonic-gate 		}
12730Sstevel@tonic-gate 		ifs.int_brdaddr = sinp->sin_addr.s_addr;
12740Sstevel@tonic-gate 
12750Sstevel@tonic-gate 		/* Get interface metric, if possible. */
12760Sstevel@tonic-gate 		if (ioctl(sock, SIOCGLIFMETRIC, lifrp) == -1) {
12770Sstevel@tonic-gate 			if (IS_IFF_UP(ifs.int_if_flags)) {
12780Sstevel@tonic-gate 				if (!(prev_complaints & COMP_BAD_METRIC))
12790Sstevel@tonic-gate 					writelog(LOG_NOTICE,
12800Sstevel@tonic-gate 					    "%s has no metric: %s",
12810Sstevel@tonic-gate 					    ifs.int_name, rip_strerror(errno));
12820Sstevel@tonic-gate 				complaints |= COMP_BAD_METRIC;
12830Sstevel@tonic-gate 			}
12840Sstevel@tonic-gate 		} else {
12850Sstevel@tonic-gate 			ifs.int_metric = lifrp->lifr_metric;
12860Sstevel@tonic-gate 			if (ifs.int_metric > HOPCNT_INFINITY) {
12870Sstevel@tonic-gate 				if (IS_IFF_UP(ifs.int_if_flags)) {
12880Sstevel@tonic-gate 					if (!(prev_complaints &
12890Sstevel@tonic-gate 					    COMP_BAD_METRIC))
12900Sstevel@tonic-gate 						writelog(LOG_NOTICE,
12910Sstevel@tonic-gate 						    "%s has a metric of %d, "
12920Sstevel@tonic-gate 						    "defaulting to %d",
12930Sstevel@tonic-gate 						    ifs.int_name,
12940Sstevel@tonic-gate 						    ifs.int_metric,
12950Sstevel@tonic-gate 						    HOPCNT_INFINITY);
12960Sstevel@tonic-gate 					complaints |= COMP_BAD_METRIC;
12970Sstevel@tonic-gate 				}
12980Sstevel@tonic-gate 				ifs.int_metric = HOPCNT_INFINITY;
12990Sstevel@tonic-gate 			}
13000Sstevel@tonic-gate 		}
13010Sstevel@tonic-gate 
13020Sstevel@tonic-gate 		ifs.int_state |= IS_CHECKED;
13030Sstevel@tonic-gate 		ifs.int_query_time = NEVER;
13040Sstevel@tonic-gate 
13050Sstevel@tonic-gate 		/*
13060Sstevel@tonic-gate 		 * If this is an alias, then mark it appropriately.
13070Sstevel@tonic-gate 		 * Do not output RIP or Router-Discovery packets via
13080Sstevel@tonic-gate 		 * aliases.
13090Sstevel@tonic-gate 		 */
13100Sstevel@tonic-gate 		if (strchr(ifs.int_name, ':') != NULL)
13110Sstevel@tonic-gate 			ifs.int_state |= IS_ALIAS;
13120Sstevel@tonic-gate 
13130Sstevel@tonic-gate 		if (ifs.int_if_flags & IFF_LOOPBACK) {
13140Sstevel@tonic-gate 			ifs.int_state |= IS_PASSIVE | IS_NO_RIP | IS_NO_RDISC;
13150Sstevel@tonic-gate 			ifs.int_dstaddr = ifs.int_addr;
13160Sstevel@tonic-gate 			ifs.int_mask = HOST_MASK;
13170Sstevel@tonic-gate 			ifs.int_ripv1_mask = HOST_MASK;
13180Sstevel@tonic-gate 			ifs.int_std_mask = std_mask(ifs.int_dstaddr);
13190Sstevel@tonic-gate 			ifs.int_net = ntohl(ifs.int_dstaddr);
13200Sstevel@tonic-gate 			if (!foundloopback) {
13210Sstevel@tonic-gate 				foundloopback = _B_TRUE;
13220Sstevel@tonic-gate 				loopaddr = ifs.int_addr;
13230Sstevel@tonic-gate 				loop_rts.rts_gate = loopaddr;
13240Sstevel@tonic-gate 				loop_rts.rts_router = loopaddr;
13250Sstevel@tonic-gate 			}
13260Sstevel@tonic-gate 
13270Sstevel@tonic-gate 		} else if (ifs.int_if_flags & IFF_POINTOPOINT) {
13280Sstevel@tonic-gate 			ifs.int_ripv1_mask = ifs.int_mask;
13290Sstevel@tonic-gate 			ifs.int_mask = HOST_MASK;
13300Sstevel@tonic-gate 			ifs.int_std_mask = std_mask(ifs.int_dstaddr);
13310Sstevel@tonic-gate 
13320Sstevel@tonic-gate 		} else {
13330Sstevel@tonic-gate 			ifs.int_dstaddr = ifs.int_addr;
13340Sstevel@tonic-gate 			ifs.int_ripv1_mask = ifs.int_mask;
13350Sstevel@tonic-gate 			ifs.int_std_mask = std_mask(ifs.int_addr);
13360Sstevel@tonic-gate 			ifs.int_net = ntohl(ifs.int_addr) & ifs.int_mask;
13370Sstevel@tonic-gate 			if (ifs.int_mask != ifs.int_std_mask)
13380Sstevel@tonic-gate 				ifs.int_state |= IS_SUBNET;
13390Sstevel@tonic-gate 		}
13400Sstevel@tonic-gate 		ifs.int_std_net = ifs.int_net & ifs.int_std_mask;
13410Sstevel@tonic-gate 		ifs.int_std_addr = htonl(ifs.int_std_net);
13420Sstevel@tonic-gate 
13430Sstevel@tonic-gate 		/*
13440Sstevel@tonic-gate 		 * If this interface duplicates another, mark it
13450Sstevel@tonic-gate 		 * appropriately so that we don't generate duplicate
13460Sstevel@tonic-gate 		 * packets.
13470Sstevel@tonic-gate 		 */
13480Sstevel@tonic-gate 		ifp = check_dup(ifs.int_name, ifs.int_addr, ifs.int_dstaddr,
13490Sstevel@tonic-gate 		    ifs.int_mask, ifs.int_if_flags, _B_FALSE);
13500Sstevel@tonic-gate 		if (ifp != NULL) {
13510Sstevel@tonic-gate 			trace_misc("%s (%s%s%s) is a duplicate of %s (%s%s%s)",
13520Sstevel@tonic-gate 			    ifs.int_name,
13530Sstevel@tonic-gate 			    addrname(ifs.int_addr, ifs.int_mask, 1),
13540Sstevel@tonic-gate 			    ((ifs.int_if_flags & IFF_POINTOPOINT) ?
13554513Skcpoon 			    "-->" : ""),
13560Sstevel@tonic-gate 			    ((ifs.int_if_flags & IFF_POINTOPOINT) ?
13574513Skcpoon 			    naddr_ntoa(ifs.int_dstaddr) : ""),
13580Sstevel@tonic-gate 			    ifp->int_name,
13590Sstevel@tonic-gate 			    addrname(ifp->int_addr, ifp->int_mask, 1),
13600Sstevel@tonic-gate 			    ((ifp->int_if_flags & IFF_POINTOPOINT) ?
13614513Skcpoon 			    "-->" : ""),
13620Sstevel@tonic-gate 			    ((ifp->int_if_flags & IFF_POINTOPOINT) ?
13634513Skcpoon 			    naddr_ntoa(ifp->int_dstaddr) : ""));
13640Sstevel@tonic-gate 			ifs.int_state |= IS_DUP;
13650Sstevel@tonic-gate 		} else {
13660Sstevel@tonic-gate 			ifs.int_state &= ~IS_DUP;
13670Sstevel@tonic-gate 		}
13680Sstevel@tonic-gate 
13690Sstevel@tonic-gate 		/*
13700Sstevel@tonic-gate 		 * See if this is a familiar interface.
13710Sstevel@tonic-gate 		 * If so, stop worrying about it if it is the same.
13720Sstevel@tonic-gate 		 * Start it over if it now is to somewhere else, as happens
13730Sstevel@tonic-gate 		 * frequently with PPP and SLIP, or if its forwarding
13740Sstevel@tonic-gate 		 * status has changed.
13750Sstevel@tonic-gate 		 */
13760Sstevel@tonic-gate 		ifp = ifwithname(ifs.int_name);
13770Sstevel@tonic-gate 		if (ifp != NULL) {
13780Sstevel@tonic-gate 			ifp->int_state |= IS_CHECKED;
13790Sstevel@tonic-gate 			ifp->int_state = (ifp->int_state & ~IS_DUP) |
13800Sstevel@tonic-gate 			    (ifs.int_state & IS_DUP);
13810Sstevel@tonic-gate 
13820Sstevel@tonic-gate 			if ((ifp->int_phys == NULL && ifindex != 0) ||
13830Sstevel@tonic-gate 			    (ifp->int_phys != NULL &&
13844513Skcpoon 			    ifp->int_phys->phyi_index != ifindex) ||
13850Sstevel@tonic-gate 			    0 != ((ifp->int_if_flags ^ ifs.int_if_flags)
13864513Skcpoon 			    & (IFF_BROADCAST | IFF_LOOPBACK |
13874513Skcpoon 			    IFF_POINTOPOINT | IFF_MULTICAST |
13884513Skcpoon 			    IFF_ROUTER | IFF_NORTEXCH | IFF_NOXMIT)) ||
13890Sstevel@tonic-gate 			    ifp->int_addr != ifs.int_addr ||
13900Sstevel@tonic-gate 			    ifp->int_brdaddr != ifs.int_brdaddr ||
13910Sstevel@tonic-gate 			    ifp->int_dstaddr != ifs.int_dstaddr ||
13920Sstevel@tonic-gate 			    ifp->int_mask != ifs.int_mask ||
13930Sstevel@tonic-gate 			    ifp->int_metric != ifs.int_metric) {
13940Sstevel@tonic-gate 				/*
13950Sstevel@tonic-gate 				 * Forget old information about
13960Sstevel@tonic-gate 				 * a changed interface.
13970Sstevel@tonic-gate 				 */
13980Sstevel@tonic-gate 				trace_act("interface %s has changed",
13990Sstevel@tonic-gate 				    ifp->int_name);
14000Sstevel@tonic-gate 				ifdel(ifp);
14010Sstevel@tonic-gate 				ifp = NULL;
14020Sstevel@tonic-gate 			}
14030Sstevel@tonic-gate 		}
14040Sstevel@tonic-gate 
14050Sstevel@tonic-gate 		if (ifp != NULL) {
14060Sstevel@tonic-gate 			/* note interfaces that have been turned off */
14070Sstevel@tonic-gate 			if (!IS_IFF_UP(ifs.int_if_flags)) {
14080Sstevel@tonic-gate 				if (IS_IFF_UP(ifp->int_if_flags)) {
14090Sstevel@tonic-gate 					writelog(LOG_WARNING,
14100Sstevel@tonic-gate 					    "interface %s to %s turned off",
14110Sstevel@tonic-gate 					    ifp->int_name,
14120Sstevel@tonic-gate 					    naddr_ntoa(ifp->int_dstaddr));
14130Sstevel@tonic-gate 					if_bad(ifp, _B_FALSE);
14140Sstevel@tonic-gate 					ifp->int_if_flags &= ~IFF_UP;
14150Sstevel@tonic-gate 				} else if (ifp->int_phys != NULL &&
14160Sstevel@tonic-gate 				    now.tv_sec > (ifp->int_phys->phyi_data.ts +
14170Sstevel@tonic-gate 				    CHECK_BAD_INTERVAL)) {
14180Sstevel@tonic-gate 					trace_act("interface %s has been off"
14190Sstevel@tonic-gate 					    " %ld seconds; forget it",
14200Sstevel@tonic-gate 					    ifp->int_name,
14210Sstevel@tonic-gate 					    now.tv_sec -
14220Sstevel@tonic-gate 					    ifp->int_phys->phyi_data.ts);
14230Sstevel@tonic-gate 					ifdel(ifp);
14240Sstevel@tonic-gate 				}
14250Sstevel@tonic-gate 				continue;
14260Sstevel@tonic-gate 			}
14270Sstevel@tonic-gate 			/* or that were off and are now ok */
14280Sstevel@tonic-gate 			if (!IS_IFF_UP(ifp->int_if_flags)) {
14290Sstevel@tonic-gate 				ifp->int_if_flags |= IFF_UP;
14300Sstevel@tonic-gate 				if_ok(ifp, "", _B_FALSE);
14310Sstevel@tonic-gate 			}
14320Sstevel@tonic-gate 
14330Sstevel@tonic-gate 			/*
14340Sstevel@tonic-gate 			 * If it has been long enough,
14350Sstevel@tonic-gate 			 * see if the interface is broken.
14360Sstevel@tonic-gate 			 */
14370Sstevel@tonic-gate 			if ((phyi = ifp->int_phys) == NULL ||
14380Sstevel@tonic-gate 			    now.tv_sec < phyi->phyi_data.ts +
14390Sstevel@tonic-gate 			    CHECK_BAD_INTERVAL)
14400Sstevel@tonic-gate 				continue;
14410Sstevel@tonic-gate 
14420Sstevel@tonic-gate 			(void) memset(&newstats, 0, sizeof (newstats));
14430Sstevel@tonic-gate 			if (get_if_kstats(ifp, &newstats) == -1) {
14440Sstevel@tonic-gate 				if (!(prev_complaints & COMP_NO_KSTATS))
14450Sstevel@tonic-gate 					writelog(LOG_WARNING,
14460Sstevel@tonic-gate 					    "unable to obtain kstats for %s",
14470Sstevel@tonic-gate 					    phyi->phyi_name);
14480Sstevel@tonic-gate 				complaints |= COMP_NO_KSTATS;
14490Sstevel@tonic-gate 			}
14500Sstevel@tonic-gate 
14510Sstevel@tonic-gate 			/*
14520Sstevel@tonic-gate 			 * If the interface just awoke, restart the counters.
14530Sstevel@tonic-gate 			 */
14540Sstevel@tonic-gate 			if (phyi->phyi_data.ts == 0) {
14550Sstevel@tonic-gate 				phyi->phyi_data = newstats;
14560Sstevel@tonic-gate 				continue;
14570Sstevel@tonic-gate 			}
14580Sstevel@tonic-gate 
14590Sstevel@tonic-gate 			in = newstats.ipackets - phyi->phyi_data.ipackets;
14600Sstevel@tonic-gate 			ierr = newstats.ierrors - phyi->phyi_data.ierrors;
14610Sstevel@tonic-gate 			out = newstats.opackets - phyi->phyi_data.opackets;
14620Sstevel@tonic-gate 			oerr = newstats.oerrors - phyi->phyi_data.oerrors;
14630Sstevel@tonic-gate 			phyi->phyi_data = newstats;
14640Sstevel@tonic-gate 
14650Sstevel@tonic-gate 			/*
14660Sstevel@tonic-gate 			 * Withhold judgment when the short error counters
14670Sstevel@tonic-gate 			 * wrap, the interface is reset, or if there are
14680Sstevel@tonic-gate 			 * no kstats.
14690Sstevel@tonic-gate 			 */
14700Sstevel@tonic-gate 			if (ierr < 0 || in < 0 || oerr < 0 || out < 0 ||
14710Sstevel@tonic-gate 			    newstats.ts == 0) {
14720Sstevel@tonic-gate 				LIM_SEC(ifscan_timer,
14730Sstevel@tonic-gate 				    now.tv_sec + CHECK_BAD_INTERVAL);
14740Sstevel@tonic-gate 				continue;
14750Sstevel@tonic-gate 			}
14760Sstevel@tonic-gate 
14770Sstevel@tonic-gate 			/* Withhold judgement when there is no traffic */
14780Sstevel@tonic-gate 			if (in == 0 && out == 0 && ierr == 0 && oerr == 0)
14790Sstevel@tonic-gate 				continue;
14800Sstevel@tonic-gate 
14810Sstevel@tonic-gate 			/*
14820Sstevel@tonic-gate 			 * It is bad if at least 25% of input or output on
14830Sstevel@tonic-gate 			 * an interface results in errors.  Require
14840Sstevel@tonic-gate 			 * presistent problems before marking it dead.
14850Sstevel@tonic-gate 			 */
14860Sstevel@tonic-gate 			if ((ierr > 0 && ierr >= in/4) ||
14870Sstevel@tonic-gate 			    (oerr > 0 && oerr >= out/4)) {
14880Sstevel@tonic-gate 				if (!(ifp->int_state & IS_SICK)) {
14890Sstevel@tonic-gate 					trace_act("interface %s to %s"
14900Sstevel@tonic-gate 					    " sick: in=%d ierr=%d"
14910Sstevel@tonic-gate 					    " out=%d oerr=%d",
14920Sstevel@tonic-gate 					    ifp->int_name,
14930Sstevel@tonic-gate 					    naddr_ntoa(ifp->int_dstaddr),
14940Sstevel@tonic-gate 					    in, ierr, out, oerr);
14950Sstevel@tonic-gate 					if_sick(ifp, _B_TRUE);
14960Sstevel@tonic-gate 					continue;
14970Sstevel@tonic-gate 				}
14980Sstevel@tonic-gate 				if (!(ifp->int_state & IS_BROKE)) {
14990Sstevel@tonic-gate 					writelog(LOG_WARNING,
15000Sstevel@tonic-gate 					    "interface %s to %s broken:"
15010Sstevel@tonic-gate 					    " in=%d ierr=%d out=%d oerr=%d",
15020Sstevel@tonic-gate 					    ifp->int_name,
15030Sstevel@tonic-gate 					    naddr_ntoa(ifp->int_dstaddr),
15040Sstevel@tonic-gate 					    in, ierr, out, oerr);
15050Sstevel@tonic-gate 					if_bad(ifp, _B_TRUE);
15060Sstevel@tonic-gate 				}
15070Sstevel@tonic-gate 				continue;
15080Sstevel@tonic-gate 			}
15090Sstevel@tonic-gate 
15100Sstevel@tonic-gate 			/* otherwise, it is active and healthy */
15110Sstevel@tonic-gate 			ifp->int_act_time = now.tv_sec;
15120Sstevel@tonic-gate 			if_ok(ifp, "", _B_TRUE);
15130Sstevel@tonic-gate 			continue;
15140Sstevel@tonic-gate 		}
15150Sstevel@tonic-gate 
15160Sstevel@tonic-gate 		/*
15170Sstevel@tonic-gate 		 * This is a new interface.
15180Sstevel@tonic-gate 		 * If it is dead, forget it.
15190Sstevel@tonic-gate 		 */
15200Sstevel@tonic-gate 		if (!IS_IFF_UP(ifs.int_if_flags))
15210Sstevel@tonic-gate 			continue;
15220Sstevel@tonic-gate 
15230Sstevel@tonic-gate 		if (0 == (ifs.int_if_flags & (IFF_POINTOPOINT |
15240Sstevel@tonic-gate 		    IFF_BROADCAST | IFF_LOOPBACK)) &&
15250Sstevel@tonic-gate 		    !(ifs.int_state & IS_PASSIVE)) {
15260Sstevel@tonic-gate 			if (!(prev_complaints & COMP_BAD_FLAGS))
15270Sstevel@tonic-gate 				trace_act("%s is neither broadcast, "
15280Sstevel@tonic-gate 				    "point-to-point, nor loopback",
15290Sstevel@tonic-gate 				    ifs.int_name);
15300Sstevel@tonic-gate 			complaints |= COMP_BAD_FLAGS;
15310Sstevel@tonic-gate 			if (!(ifs.int_if_flags & IFF_MULTICAST))
15320Sstevel@tonic-gate 				ifs.int_state |= IS_NO_RDISC;
15330Sstevel@tonic-gate 		}
15340Sstevel@tonic-gate 
15350Sstevel@tonic-gate 
15360Sstevel@tonic-gate 		/*
15370Sstevel@tonic-gate 		 * It is new and ok.   Add it to the list of interfaces
15380Sstevel@tonic-gate 		 */
15390Sstevel@tonic-gate 		ifp = rtmalloc(sizeof (*ifp), "ifscan ifp");
15400Sstevel@tonic-gate 		(void) memcpy(ifp, &ifs, sizeof (*ifp));
15410Sstevel@tonic-gate 		get_parms(ifp);
15420Sstevel@tonic-gate 		if_link(ifp, ifindex);
15430Sstevel@tonic-gate 		trace_if("Add", ifp);
15440Sstevel@tonic-gate 
15450Sstevel@tonic-gate 		if (ifp->int_phys != NULL &&
15460Sstevel@tonic-gate 		    get_if_kstats(ifp, &ifp->int_phys->phyi_data) == -1) {
15470Sstevel@tonic-gate 			if (!(prev_complaints & COMP_NO_KSTATS))
15480Sstevel@tonic-gate 				writelog(LOG_NOTICE,
15490Sstevel@tonic-gate 				    "unable to obtain kstats for %s",
15500Sstevel@tonic-gate 				    ifp->int_phys->phyi_name);
15510Sstevel@tonic-gate 			complaints |= COMP_NO_KSTATS;
15520Sstevel@tonic-gate 		}
15530Sstevel@tonic-gate 
15540Sstevel@tonic-gate 		/* Detect interfaces that have conflicting netmasks. */
15550Sstevel@tonic-gate 		if (!(ifp->int_if_flags & (IFF_POINTOPOINT|IFF_LOOPBACK))) {
15560Sstevel@tonic-gate 			for (ifp1 = ifnet; ifp1 != NULL;
15570Sstevel@tonic-gate 			    ifp1 = ifp1->int_next) {
15580Sstevel@tonic-gate 				if (ifp1->int_mask == ifp->int_mask)
15590Sstevel@tonic-gate 					continue;
15600Sstevel@tonic-gate 
15610Sstevel@tonic-gate 				/*
15620Sstevel@tonic-gate 				 * we don't care about point-to-point
15630Sstevel@tonic-gate 				 * or loopback aliases
15640Sstevel@tonic-gate 				 */
15650Sstevel@tonic-gate 				if (ifp1->int_if_flags &
15660Sstevel@tonic-gate 				    (IFF_POINTOPOINT|IFF_LOOPBACK)) {
15670Sstevel@tonic-gate 					continue;
15680Sstevel@tonic-gate 				}
15690Sstevel@tonic-gate 
15700Sstevel@tonic-gate 				/* ignore aliases on the same network */
15710Sstevel@tonic-gate 				if (ifp->int_phys == ifp1->int_phys)
15720Sstevel@tonic-gate 					continue;
15730Sstevel@tonic-gate 
15740Sstevel@tonic-gate 				if (on_net(ifp->int_addr,
15750Sstevel@tonic-gate 				    ifp1->int_net, ifp1->int_mask) ||
15760Sstevel@tonic-gate 				    on_net(ifp1->int_addr,
15774513Skcpoon 				    ifp->int_net, ifp->int_mask)) {
15780Sstevel@tonic-gate 					writelog(LOG_INFO,
15790Sstevel@tonic-gate 					    "possible netmask problem"
15800Sstevel@tonic-gate 					    " between %s:%s and %s:%s",
15810Sstevel@tonic-gate 					    ifp->int_name,
15820Sstevel@tonic-gate 					    addrname(htonl(ifp->int_net),
15834513Skcpoon 					    ifp->int_mask, 1),
15840Sstevel@tonic-gate 					    ifp1->int_name,
15850Sstevel@tonic-gate 					    addrname(htonl(ifp1->int_net),
15864513Skcpoon 					    ifp1->int_mask, 1));
15870Sstevel@tonic-gate 					complaints |= COMP_NETMASK;
15880Sstevel@tonic-gate 				}
15890Sstevel@tonic-gate 			}
15900Sstevel@tonic-gate 		}
15910Sstevel@tonic-gate 
15920Sstevel@tonic-gate 		if (!(ifp->int_state & IS_DUP) &&
15930Sstevel@tonic-gate 		    !IS_IFF_QUIET(ifp->int_if_flags)) {
15940Sstevel@tonic-gate 			/* Count the # of directly connected networks. */
15950Sstevel@tonic-gate 			tot_interfaces++;
15960Sstevel@tonic-gate 			if (!IS_RIP_OFF(ifp->int_state))
15970Sstevel@tonic-gate 				rip_interfaces++;
15980Sstevel@tonic-gate 			if (!IS_RIP_OUT_OFF(ifp->int_state))
15990Sstevel@tonic-gate 				ripout_interfaces++;
16000Sstevel@tonic-gate 			if (IS_IFF_ROUTING(ifp->int_if_flags))
16010Sstevel@tonic-gate 				fwd_interfaces++;
16020Sstevel@tonic-gate 
16030Sstevel@tonic-gate 			if_ok_rdisc(ifp);
16040Sstevel@tonic-gate 			rip_on(ifp);
16050Sstevel@tonic-gate 		}
16060Sstevel@tonic-gate 	}
16070Sstevel@tonic-gate 
16080Sstevel@tonic-gate 	(void) close(sock);
16090Sstevel@tonic-gate 
16100Sstevel@tonic-gate 	/*
16110Sstevel@tonic-gate 	 * If we are multi-homed and have at least two interfaces that
16120Sstevel@tonic-gate 	 * are able to forward, then output RIP by default.
16130Sstevel@tonic-gate 	 */
16140Sstevel@tonic-gate 	if (!supplier_set)
16150Sstevel@tonic-gate 		set_supplier();
16160Sstevel@tonic-gate 
16170Sstevel@tonic-gate 	/*
16180Sstevel@tonic-gate 	 * If we are multi-homed, optionally advertise a route to
16190Sstevel@tonic-gate 	 * our main address.
16200Sstevel@tonic-gate 	 */
16210Sstevel@tonic-gate 	if (advertise_mhome || (tot_interfaces > 1 && mhome)) {
16220Sstevel@tonic-gate 		/* lookup myaddr if we haven't done so already */
16230Sstevel@tonic-gate 		if (myaddr == 0) {
16240Sstevel@tonic-gate 			char myname[MAXHOSTNAMELEN+1];
16250Sstevel@tonic-gate 
16260Sstevel@tonic-gate 			/*
16270Sstevel@tonic-gate 			 * If we are unable to resolve our hostname, don't
16280Sstevel@tonic-gate 			 * bother trying again.
16290Sstevel@tonic-gate 			 */
16300Sstevel@tonic-gate 			if (gethostname(myname, MAXHOSTNAMELEN) == -1) {
16310Sstevel@tonic-gate 				msglog("gethostname: %s", rip_strerror(errno));
16320Sstevel@tonic-gate 				advertise_mhome = _B_FALSE;
16330Sstevel@tonic-gate 				mhome = _B_FALSE;
16340Sstevel@tonic-gate 			} else if (gethost(myname, &myaddr) == 0) {
16350Sstevel@tonic-gate 				writelog(LOG_WARNING,
16360Sstevel@tonic-gate 				    "unable to resolve local hostname %s",
16370Sstevel@tonic-gate 				    myname);
16380Sstevel@tonic-gate 				advertise_mhome = _B_FALSE;
16390Sstevel@tonic-gate 				mhome = _B_FALSE;
16400Sstevel@tonic-gate 			}
16410Sstevel@tonic-gate 		}
16420Sstevel@tonic-gate 		if (myaddr != 0 &&
16430Sstevel@tonic-gate 		    (ifp = ifwithaddr(myaddr, _B_FALSE, _B_FALSE)) != NULL &&
16440Sstevel@tonic-gate 		    foundloopback) {
16450Sstevel@tonic-gate 			advertise_mhome = _B_TRUE;
16460Sstevel@tonic-gate 			rt = rtget(myaddr, HOST_MASK);
16470Sstevel@tonic-gate 			if (rt != NULL) {
16480Sstevel@tonic-gate 				if (rt->rt_ifp != ifp ||
16490Sstevel@tonic-gate 				    rt->rt_router != loopaddr) {
16500Sstevel@tonic-gate 					rtdelete(rt);
16510Sstevel@tonic-gate 					rt = NULL;
16520Sstevel@tonic-gate 				} else {
16530Sstevel@tonic-gate 					loop_rts.rts_ifp = ifp;
16540Sstevel@tonic-gate 					loop_rts.rts_metric = 0;
16550Sstevel@tonic-gate 					loop_rts.rts_time = rt->rt_time;
16560Sstevel@tonic-gate 					loop_rts.rts_origin = RO_LOOPBCK;
16570Sstevel@tonic-gate 					rtchange(rt, rt->rt_state | RS_MHOME,
16580Sstevel@tonic-gate 					    &loop_rts, NULL);
16590Sstevel@tonic-gate 				}
16600Sstevel@tonic-gate 			}
16610Sstevel@tonic-gate 			if (rt == NULL) {
16620Sstevel@tonic-gate 				loop_rts.rts_ifp = ifp;
16630Sstevel@tonic-gate 				loop_rts.rts_metric = 0;
16640Sstevel@tonic-gate 				loop_rts.rts_origin = RO_LOOPBCK;
16650Sstevel@tonic-gate 				rtadd(myaddr, HOST_MASK, RS_MHOME, &loop_rts);
16660Sstevel@tonic-gate 			}
16670Sstevel@tonic-gate 		}
16680Sstevel@tonic-gate 	}
16690Sstevel@tonic-gate 
16700Sstevel@tonic-gate 	for (ifp = ifnet; ifp != NULL; ifp = ifp1) {
16710Sstevel@tonic-gate 		ifp1 = ifp->int_next;	/* because we may delete it */
16720Sstevel@tonic-gate 
16730Sstevel@tonic-gate 		/* Forget any interfaces that have disappeared. */
16740Sstevel@tonic-gate 		if (!(ifp->int_state & (IS_CHECKED | IS_REMOTE))) {
16750Sstevel@tonic-gate 			trace_act("interface %s has disappeared",
16760Sstevel@tonic-gate 			    ifp->int_name);
16770Sstevel@tonic-gate 			ifdel(ifp);
16780Sstevel@tonic-gate 			continue;
16790Sstevel@tonic-gate 		}
16800Sstevel@tonic-gate 
16810Sstevel@tonic-gate 		if ((ifp->int_state & IS_BROKE) &&
16820Sstevel@tonic-gate 		    !(ifp->int_state & IS_PASSIVE))
16830Sstevel@tonic-gate 			LIM_SEC(ifscan_timer, now.tv_sec+CHECK_BAD_INTERVAL);
16840Sstevel@tonic-gate 
16850Sstevel@tonic-gate 		/*
16860Sstevel@tonic-gate 		 * If we ever have a RIPv1 interface, assume we always will.
16870Sstevel@tonic-gate 		 * It might come back if it ever goes away.
16880Sstevel@tonic-gate 		 */
16890Sstevel@tonic-gate 		if (!(ifp->int_state & (IS_NO_RIPV1_OUT | IS_DUP)) &&
16900Sstevel@tonic-gate 		    should_supply(ifp))
16910Sstevel@tonic-gate 			have_ripv1_out = _B_TRUE;
16920Sstevel@tonic-gate 		if (!(ifp->int_state & IS_NO_RIPV1_IN))
16930Sstevel@tonic-gate 			have_ripv1_in = _B_TRUE;
16940Sstevel@tonic-gate 	}
16950Sstevel@tonic-gate 
16960Sstevel@tonic-gate 	for (ifp = ifnet; ifp != NULL; ifp = ifp->int_next) {
16970Sstevel@tonic-gate 		/*
16980Sstevel@tonic-gate 		 * Ensure there is always a network route for interfaces,
16990Sstevel@tonic-gate 		 * after any dead interfaces have been deleted, which
17000Sstevel@tonic-gate 		 * might affect routes for point-to-point links.
17010Sstevel@tonic-gate 		 */
17020Sstevel@tonic-gate 		if (addrouteforif(ifp) == 0)
17030Sstevel@tonic-gate 			continue;
17040Sstevel@tonic-gate 
17050Sstevel@tonic-gate 		/*
17060Sstevel@tonic-gate 		 * Add routes to the local end of point-to-point interfaces
17070Sstevel@tonic-gate 		 * using loopback.
17080Sstevel@tonic-gate 		 */
17090Sstevel@tonic-gate 		if ((ifp->int_if_flags & IFF_POINTOPOINT) &&
17100Sstevel@tonic-gate 		    !(ifp->int_state & IS_REMOTE) && foundloopback) {
17110Sstevel@tonic-gate 			/*
17120Sstevel@tonic-gate 			 * Delete any routes to the network address through
17130Sstevel@tonic-gate 			 * foreign routers. Remove even static routes.
17140Sstevel@tonic-gate 			 */
17150Sstevel@tonic-gate 			del_static(ifp->int_addr, HOST_MASK, 0, ifp, 0);
17160Sstevel@tonic-gate 			rt = rtget(ifp->int_addr, HOST_MASK);
17170Sstevel@tonic-gate 			if (rt != NULL && rt->rt_router != loopaddr) {
17180Sstevel@tonic-gate 				rtdelete(rt);
17190Sstevel@tonic-gate 				rt = NULL;
17200Sstevel@tonic-gate 			}
17210Sstevel@tonic-gate 			if (rt != NULL) {
17220Sstevel@tonic-gate 				if (!(rt->rt_state & RS_LOCAL) ||
17230Sstevel@tonic-gate 				    rt->rt_metric > ifp->int_metric) {
17240Sstevel@tonic-gate 					ifp1 = ifp;
17250Sstevel@tonic-gate 				} else {
17260Sstevel@tonic-gate 					ifp1 = rt->rt_ifp;
17270Sstevel@tonic-gate 				}
17280Sstevel@tonic-gate 				loop_rts.rts_ifp = ifp1;
17290Sstevel@tonic-gate 				loop_rts.rts_metric = 0;
17300Sstevel@tonic-gate 				loop_rts.rts_time = rt->rt_time;
17310Sstevel@tonic-gate 				loop_rts.rts_origin = RO_LOOPBCK;
17320Sstevel@tonic-gate 				rtchange(rt, ((rt->rt_state & ~RS_NET_SYN) |
17330Sstevel@tonic-gate 				    (RS_IF|RS_LOCAL)), &loop_rts, 0);
17340Sstevel@tonic-gate 			} else {
17350Sstevel@tonic-gate 				loop_rts.rts_ifp = ifp;
17360Sstevel@tonic-gate 				loop_rts.rts_metric = 0;
17370Sstevel@tonic-gate 				loop_rts.rts_origin = RO_LOOPBCK;
17380Sstevel@tonic-gate 				rtadd(ifp->int_addr, HOST_MASK,
17390Sstevel@tonic-gate 				    (RS_IF | RS_LOCAL), &loop_rts);
17400Sstevel@tonic-gate 			}
17410Sstevel@tonic-gate 		}
17420Sstevel@tonic-gate 	}
17430Sstevel@tonic-gate 
17440Sstevel@tonic-gate 	/* add the authority routes */
17450Sstevel@tonic-gate 	for (intnetp = intnets; intnetp != NULL;
17460Sstevel@tonic-gate 	    intnetp = intnetp->intnet_next) {
17470Sstevel@tonic-gate 		rt = rtget(intnetp->intnet_addr, intnetp->intnet_mask);
17480Sstevel@tonic-gate 		if (rt != NULL &&
17490Sstevel@tonic-gate 		    !(rt->rt_state & RS_NO_NET_SYN) &&
17500Sstevel@tonic-gate 		    !(rt->rt_state & RS_NET_INT)) {
17510Sstevel@tonic-gate 			rtdelete(rt);
17520Sstevel@tonic-gate 			rt = NULL;
17530Sstevel@tonic-gate 		}
17540Sstevel@tonic-gate 		if (rt == NULL) {
17550Sstevel@tonic-gate 			loop_rts.rts_ifp = NULL;
17560Sstevel@tonic-gate 			loop_rts.rts_metric = intnetp->intnet_metric-1;
17570Sstevel@tonic-gate 			loop_rts.rts_origin = RO_LOOPBCK;
17580Sstevel@tonic-gate 			rtadd(intnetp->intnet_addr, intnetp->intnet_mask,
17590Sstevel@tonic-gate 			    RS_NET_SYN | RS_NET_INT, &loop_rts);
17600Sstevel@tonic-gate 		}
17610Sstevel@tonic-gate 	}
17620Sstevel@tonic-gate 
17630Sstevel@tonic-gate 	prev_complaints = complaints;
17640Sstevel@tonic-gate }
17650Sstevel@tonic-gate 
17660Sstevel@tonic-gate 
17670Sstevel@tonic-gate static void
check_net_syn(struct interface * ifp)17680Sstevel@tonic-gate check_net_syn(struct interface *ifp)
17690Sstevel@tonic-gate {
17700Sstevel@tonic-gate 	struct rt_entry *rt;
17710Sstevel@tonic-gate 	struct rt_spare new;
17720Sstevel@tonic-gate 
17730Sstevel@tonic-gate 	/*
17740Sstevel@tonic-gate 	 * Turn on the need to automatically synthesize a network route
17750Sstevel@tonic-gate 	 * for this interface only if we are running RIPv1 on some other
17760Sstevel@tonic-gate 	 * interface that is on a different class-A,B,or C network.
17770Sstevel@tonic-gate 	 */
17780Sstevel@tonic-gate 	if (have_ripv1_out || have_ripv1_in) {
17790Sstevel@tonic-gate 		ifp->int_state |= IS_NEED_NET_SYN;
17800Sstevel@tonic-gate 		rt = rtget(ifp->int_std_addr, ifp->int_std_mask);
17810Sstevel@tonic-gate 		if (rt != NULL &&
17820Sstevel@tonic-gate 		    0 == (rt->rt_state & RS_NO_NET_SYN) &&
17830Sstevel@tonic-gate 		    (!(rt->rt_state & RS_NET_SYN) ||
17844513Skcpoon 		    rt->rt_metric > ifp->int_metric)) {
17850Sstevel@tonic-gate 			rtdelete(rt);
17860Sstevel@tonic-gate 			rt = NULL;
17870Sstevel@tonic-gate 		}
17880Sstevel@tonic-gate 		if (rt == NULL) {
17890Sstevel@tonic-gate 			(void) memset(&new, 0, sizeof (new));
17900Sstevel@tonic-gate 			new.rts_ifp = ifp;
17910Sstevel@tonic-gate 			new.rts_gate = ifp->int_addr;
17920Sstevel@tonic-gate 			new.rts_router = ifp->int_addr;
17930Sstevel@tonic-gate 			new.rts_metric = ifp->int_metric;
17940Sstevel@tonic-gate 			new.rts_origin = RO_NET_SYN;
17950Sstevel@tonic-gate 			rtadd(ifp->int_std_addr, ifp->int_std_mask,
17960Sstevel@tonic-gate 			    RS_NET_SYN, &new);
17970Sstevel@tonic-gate 		}
17980Sstevel@tonic-gate 
17990Sstevel@tonic-gate 	} else {
18000Sstevel@tonic-gate 		ifp->int_state &= ~IS_NEED_NET_SYN;
18010Sstevel@tonic-gate 
18020Sstevel@tonic-gate 		rt = rtget(ifp->int_std_addr, ifp->int_std_mask);
18030Sstevel@tonic-gate 		if (rt != NULL &&
18040Sstevel@tonic-gate 		    (rt->rt_state & RS_NET_SYN) &&
18050Sstevel@tonic-gate 		    rt->rt_ifp == ifp)
18060Sstevel@tonic-gate 			rtbad_sub(rt, NULL);
18070Sstevel@tonic-gate 	}
18080Sstevel@tonic-gate }
18090Sstevel@tonic-gate 
18100Sstevel@tonic-gate 
18110Sstevel@tonic-gate /*
18120Sstevel@tonic-gate  * Add route for interface if not currently installed.
18130Sstevel@tonic-gate  * Create route to other end if a point-to-point link,
18140Sstevel@tonic-gate  * otherwise a route to this (sub)network.
18150Sstevel@tonic-gate  */
18160Sstevel@tonic-gate static boolean_t			/* _B_FALSE=bad interface */
addrouteforif(struct interface * ifp)18170Sstevel@tonic-gate addrouteforif(struct interface *ifp)
18180Sstevel@tonic-gate {
18190Sstevel@tonic-gate 	struct rt_entry *rt;
18200Sstevel@tonic-gate 	struct rt_spare new;
18210Sstevel@tonic-gate 	in_addr_t dst;
18220Sstevel@tonic-gate 	uint16_t rt_newstate = RS_IF;
18230Sstevel@tonic-gate 
18240Sstevel@tonic-gate 
18250Sstevel@tonic-gate 	/* skip sick interfaces */
18260Sstevel@tonic-gate 	if (ifp->int_state & IS_BROKE)
18270Sstevel@tonic-gate 		return (_B_FALSE);
18280Sstevel@tonic-gate 
18290Sstevel@tonic-gate 	/*
18300Sstevel@tonic-gate 	 * don't install routes for duplicate interfaces, or
18310Sstevel@tonic-gate 	 * unnumbered point-to-point interfaces.
18320Sstevel@tonic-gate 	 */
18330Sstevel@tonic-gate 	if ((ifp->int_state & IS_DUP) ||
18340Sstevel@tonic-gate 	    ((ifp->int_if_flags & IFF_POINTOPOINT) && ifp->int_dstaddr == 0))
18350Sstevel@tonic-gate 		return (_B_TRUE);
18360Sstevel@tonic-gate 
18370Sstevel@tonic-gate 	/*
18380Sstevel@tonic-gate 	 * If the interface on a subnet, then install a RIPv1 route to
18390Sstevel@tonic-gate 	 * the network as well (unless it is sick).
18400Sstevel@tonic-gate 	 */
18410Sstevel@tonic-gate 	if (ifp->int_state & IS_SUBNET)
18420Sstevel@tonic-gate 		check_net_syn(ifp);
18430Sstevel@tonic-gate 
18440Sstevel@tonic-gate 	dst = (0 != (ifp->int_if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) ?
18450Sstevel@tonic-gate 	    ifp->int_dstaddr : htonl(ifp->int_net));
18460Sstevel@tonic-gate 
18470Sstevel@tonic-gate 	(void) memset(&new, 0, sizeof (new));
18480Sstevel@tonic-gate 	new.rts_ifp = ifp;
18490Sstevel@tonic-gate 	new.rts_router = ifp->int_addr;
18500Sstevel@tonic-gate 	new.rts_gate = ifp->int_addr;
18510Sstevel@tonic-gate 	new.rts_metric = ifp->int_metric;
18520Sstevel@tonic-gate 	new.rts_time = now.tv_sec;
18530Sstevel@tonic-gate 	if (ifp->int_if_flags & IFF_POINTOPOINT)
18540Sstevel@tonic-gate 		new.rts_origin = RO_PTOPT;
18550Sstevel@tonic-gate 	else if (ifp->int_if_flags & IFF_LOOPBACK)
18560Sstevel@tonic-gate 		new.rts_origin = RO_LOOPBCK;
18570Sstevel@tonic-gate 	else
18580Sstevel@tonic-gate 		new.rts_origin = RO_IF;
18590Sstevel@tonic-gate 
18600Sstevel@tonic-gate 	/*
18610Sstevel@tonic-gate 	 * If we are going to send packets to the gateway,
18620Sstevel@tonic-gate 	 * it must be reachable using our physical interfaces
18630Sstevel@tonic-gate 	 */
18640Sstevel@tonic-gate 	if ((ifp->int_state & IS_REMOTE) &&
18650Sstevel@tonic-gate 	    !(ifp->int_state & IS_EXTERNAL) &&
18660Sstevel@tonic-gate 	    !check_remote(ifp))
18670Sstevel@tonic-gate 		return (_B_FALSE);
18680Sstevel@tonic-gate 
18690Sstevel@tonic-gate 	/*
18700Sstevel@tonic-gate 	 * We are finished if the correct main interface route exists.
18710Sstevel@tonic-gate 	 * The right route must be for the right interface, not synthesized
18720Sstevel@tonic-gate 	 * from a subnet, be a "gateway" or not as appropriate, and so forth.
18730Sstevel@tonic-gate 	 */
18740Sstevel@tonic-gate 	del_static(dst, ifp->int_mask, 0, ifp, 0);
18750Sstevel@tonic-gate 	rt = rtget(dst, ifp->int_mask);
18760Sstevel@tonic-gate 	if (!IS_IFF_ROUTING(ifp->int_if_flags))
18770Sstevel@tonic-gate 		rt_newstate |= RS_NOPROPAGATE;
18780Sstevel@tonic-gate 	if (rt != NULL) {
18790Sstevel@tonic-gate 		if ((rt->rt_ifp != ifp || rt->rt_router != ifp->int_addr) &&
18800Sstevel@tonic-gate 		    (rt->rt_ifp == NULL ||
18810Sstevel@tonic-gate 		    (rt->rt_ifp->int_state & IS_BROKE))) {
18820Sstevel@tonic-gate 			rtdelete(rt);
18830Sstevel@tonic-gate 			rt = NULL;
18840Sstevel@tonic-gate 		} else {
18850Sstevel@tonic-gate 			rtchange(rt, ((rt->rt_state | rt_newstate) &
18860Sstevel@tonic-gate 			    ~(RS_NET_SYN | RS_LOCAL)), &new, 0);
18870Sstevel@tonic-gate 		}
18880Sstevel@tonic-gate 	}
18890Sstevel@tonic-gate 	if (rt == NULL) {
18900Sstevel@tonic-gate 		if (ifp->int_transitions++ > 0)
18910Sstevel@tonic-gate 			trace_act("re-installing interface %s;"
18920Sstevel@tonic-gate 			    " went up %d times",
18930Sstevel@tonic-gate 			    ifp->int_name, ifp->int_transitions);
18940Sstevel@tonic-gate 
18950Sstevel@tonic-gate 		rtadd(dst, ifp->int_mask, rt_newstate, &new);
18960Sstevel@tonic-gate 	}
18970Sstevel@tonic-gate 
18980Sstevel@tonic-gate 	return (_B_TRUE);
18990Sstevel@tonic-gate }
19000Sstevel@tonic-gate 
19010Sstevel@tonic-gate /*
19020Sstevel@tonic-gate  * Obtains the named kstat, and places its value in *value.  It
19030Sstevel@tonic-gate  * returns 0 for success, -1 for failure.
19040Sstevel@tonic-gate  */
19050Sstevel@tonic-gate static int
kstat_named_value(kstat_t * ksp,char * name,uint32_t * value)19060Sstevel@tonic-gate kstat_named_value(kstat_t *ksp, char *name, uint32_t *value)
19070Sstevel@tonic-gate {
19080Sstevel@tonic-gate 	kstat_named_t *knp;
19090Sstevel@tonic-gate 
19100Sstevel@tonic-gate 	if (ksp == NULL)
19110Sstevel@tonic-gate 		return (-1);
19120Sstevel@tonic-gate 
19130Sstevel@tonic-gate 	if ((knp = kstat_data_lookup(ksp, name)) == NULL) {
19140Sstevel@tonic-gate 		return (-1);
19150Sstevel@tonic-gate 	} else if (knp->data_type != KSTAT_DATA_UINT32) {
19160Sstevel@tonic-gate 		return (-1);
19170Sstevel@tonic-gate 	} else {
19180Sstevel@tonic-gate 		*value = knp->value.ui32;
19190Sstevel@tonic-gate 		return (0);
19200Sstevel@tonic-gate 	}
19210Sstevel@tonic-gate }
19220Sstevel@tonic-gate 
19230Sstevel@tonic-gate static int
get_if_kstats(struct interface * ifp,struct phyi_data * newdata)19240Sstevel@tonic-gate get_if_kstats(struct interface *ifp, struct phyi_data *newdata)
19250Sstevel@tonic-gate {
19260Sstevel@tonic-gate 	struct physical_interface *phyi = ifp->int_phys;
19270Sstevel@tonic-gate 	kstat_ctl_t *kc;
19280Sstevel@tonic-gate 	kstat_t *ksp;
19290Sstevel@tonic-gate 
19300Sstevel@tonic-gate 	/* We did this recently; don't do it again. */
19310Sstevel@tonic-gate 	if (phyi->phyi_data.ts == now.tv_sec) {
19320Sstevel@tonic-gate 		if (newdata != &phyi->phyi_data)
19330Sstevel@tonic-gate 			*newdata = phyi->phyi_data;
19340Sstevel@tonic-gate 		return (0);
19350Sstevel@tonic-gate 	}
19360Sstevel@tonic-gate 
19370Sstevel@tonic-gate 	if ((kc = kstat_open()) == NULL)
19380Sstevel@tonic-gate 		return (-1);
19390Sstevel@tonic-gate 
19405895Syz147064 	/*
19415895Syz147064 	 * First we try to query the "link" kstats in case the link is renamed.
19425895Syz147064 	 * If that fails, fallback to legacy ktats for those non-GLDv3 links.
19435895Syz147064 	 */
19445895Syz147064 	if (((ksp = kstat_lookup(kc, "link", 0, phyi->phyi_name)) == NULL) &&
19455895Syz147064 	    ((ksp = kstat_lookup(kc, NULL, -1, phyi->phyi_name)) == NULL)) {
19460Sstevel@tonic-gate 		(void) kstat_close(kc);
19470Sstevel@tonic-gate 		return (-1);
19480Sstevel@tonic-gate 	}
19490Sstevel@tonic-gate 
19500Sstevel@tonic-gate 	if (kstat_read(kc, ksp, NULL) == -1) {
19510Sstevel@tonic-gate 		(void) kstat_close(kc);
19520Sstevel@tonic-gate 		return (-1);
19530Sstevel@tonic-gate 	}
19540Sstevel@tonic-gate 
19550Sstevel@tonic-gate 	if ((kstat_named_value(ksp, "ipackets", &newdata->ipackets) == -1) ||
19560Sstevel@tonic-gate 	    (kstat_named_value(ksp, "opackets",	&newdata->opackets) == -1)) {
19570Sstevel@tonic-gate 		newdata->ts = 0;
19580Sstevel@tonic-gate 		(void) kstat_close(kc);
19590Sstevel@tonic-gate 		return (-1);
19600Sstevel@tonic-gate 	}
19610Sstevel@tonic-gate 
19620Sstevel@tonic-gate 	/* The loopback interface does not keep track of errors */
19630Sstevel@tonic-gate 	if (!(ifp->int_if_flags & IFF_LOOPBACK)) {
19640Sstevel@tonic-gate 		if ((kstat_named_value(ksp, "ierrors",
19650Sstevel@tonic-gate 		    &newdata->ierrors) == -1) ||
19660Sstevel@tonic-gate 		    (kstat_named_value(ksp, "oerrors",
19670Sstevel@tonic-gate 		    &newdata->oerrors) == -1)) {
19680Sstevel@tonic-gate 			newdata->ts = 0;
19690Sstevel@tonic-gate 			(void) kstat_close(kc);
19700Sstevel@tonic-gate 			return (-1);
19710Sstevel@tonic-gate 		}
19720Sstevel@tonic-gate 	}
19730Sstevel@tonic-gate 
19740Sstevel@tonic-gate 	newdata->ts = now.tv_sec;
19750Sstevel@tonic-gate 	(void) kstat_close(kc);
19760Sstevel@tonic-gate 	return (0);
19770Sstevel@tonic-gate }
19780Sstevel@tonic-gate 
19790Sstevel@tonic-gate /*
19800Sstevel@tonic-gate  * Returns true if we should supply routes to other systems.  If the
19810Sstevel@tonic-gate  * user has forced us to be a supplier (by the command line) or if we
19820Sstevel@tonic-gate  * have more than one forwarding interface and this is one of the
19830Sstevel@tonic-gate  * forwarding interfaces, then behave as a RIP supplier (supply rdisc
19840Sstevel@tonic-gate  * advertisements and RIP responses).
19850Sstevel@tonic-gate  */
19860Sstevel@tonic-gate boolean_t
should_supply(struct interface * ifp)19870Sstevel@tonic-gate should_supply(struct interface *ifp)
19880Sstevel@tonic-gate {
19890Sstevel@tonic-gate 	if (ifp != NULL && !IS_IFF_ROUTING(ifp->int_if_flags))
19900Sstevel@tonic-gate 		return (_B_FALSE);
19910Sstevel@tonic-gate 	return ((supplier_set && supplier) ||
19920Sstevel@tonic-gate 	    (!supplier_set && fwd_interfaces > 1));
19930Sstevel@tonic-gate }
1994