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