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