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