if.c revision 46303
1261081Sasomers/* 2261081Sasomers * Copyright (c) 1983, 1993 3261081Sasomers * The Regents of the University of California. All rights reserved. 4261081Sasomers * 5261081Sasomers * Redistribution and use in source and binary forms, with or without 6261081Sasomers * modification, are permitted provided that the following conditions 7261081Sasomers * are met: 8261081Sasomers * 1. Redistributions of source code must retain the above copyright 9261081Sasomers * notice, this list of conditions and the following disclaimer. 10261081Sasomers * 2. Redistributions in binary form must reproduce the above copyright 11261081Sasomers * notice, this list of conditions and the following disclaimer in the 12261081Sasomers * documentation and/or other materials provided with the distribution. 13261081Sasomers * 3. All advertising materials mentioning features or use of this software 14261081Sasomers * must display the following acknowledgment: 15261081Sasomers * This product includes software developed by the University of 16261081Sasomers * California, Berkeley and its contributors. 17261081Sasomers * 4. Neither the name of the University nor the names of its contributors 18261081Sasomers * may be used to endorse or promote products derived from this software 19261081Sasomers * without specific prior written permission. 20261081Sasomers * 21261081Sasomers * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22261081Sasomers * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23261081Sasomers * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24261081Sasomers * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25261081Sasomers * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26261081Sasomers * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27261081Sasomers * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28261081Sasomers * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29261081Sasomers * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30261081Sasomers * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31261081Sasomers * SUCH DAMAGE. 32261081Sasomers * 33261081Sasomers * $Id$ 34261081Sasomers */ 35261081Sasomers 36261081Sasomers#include "defs.h" 37261081Sasomers#include "pathnames.h" 38261081Sasomers 39261081Sasomers#if !defined(sgi) && !defined(__NetBSD__) 40261081Sasomersstatic char sccsid[] __attribute__((unused)) = "@(#)if.c 8.1 (Berkeley) 6/5/93"; 41261081Sasomers#elif defined(__NetBSD__) 42261081Sasomers#include <sys/cdefs.h> 43261081Sasomers__RCSID("$NetBSD$"); 44261081Sasomers#endif 45261081Sasomers#ident "$Revision: 2.17 $" 46262894Sasomers 47261081Sasomersstruct interface *ifnet; /* all interfaces */ 48261081Sasomers 49261081Sasomers/* hash table for all interfaces, big enough to tolerate ridiculous 50292820Sngie * numbers of IP aliases. Crazy numbers of aliases such as 7000 51261081Sasomers * still will not do well, but not just in looking up interfaces 52261081Sasomers * by name or address. 53261081Sasomers */ 54261081Sasomers#define AHASH_LEN 211 /* must be prime */ 55261081Sasomers#define AHASH(a) &ahash_tbl[(a)%AHASH_LEN] 56261081Sasomersstruct interface *ahash_tbl[AHASH_LEN]; 57261081Sasomers 58262894Sasomers#define BHASH_LEN 211 /* must be prime */ 59261081Sasomers#define BHASH(a) &bhash_tbl[(a)%BHASH_LEN] 60261081Sasomersstruct interface *bhash_tbl[BHASH_LEN]; 61261081Sasomers 62292820Sngiestruct interface *remote_if; /* remote interfaces */ 63261081Sasomers 64261081Sasomers/* hash for physical interface names. 65261081Sasomers * Assume there are never more 100 or 200 real interfaces, and that 66261081Sasomers * aliases are put on the end of the hash chains. 67261081Sasomers */ 68261081Sasomers#define NHASH_LEN 97 69261081Sasomersstruct interface *nhash_tbl[NHASH_LEN]; 70261081Sasomers 71261081Sasomersint tot_interfaces; /* # of remote and local interfaces */ 72292820Sngieint rip_interfaces; /* # of interfaces doing RIP */ 73261081Sasomersint foundloopback; /* valid flag for loopaddr */ 74261081Sasomersnaddr loopaddr; /* our address on loopback */ 75261081Sasomersstruct rt_spare loop_rts; 76262894Sasomers 77261081Sasomersstruct timeval ifinit_timer; 78261081Sasomersstatic struct timeval last_ifinit; 79261081Sasomers#define IF_RESCAN_DELAY() (last_ifinit.tv_sec == now.tv_sec \ 80261081Sasomers && last_ifinit.tv_usec == now.tv_usec \ 81261081Sasomers && timercmp(&ifinit_timer, &now, >)) 82261081Sasomers 83261081Sasomersint have_ripv1_out; /* have a RIPv1 interface */ 84261081Sasomersint have_ripv1_in; 85261081Sasomers 86261081Sasomers 87261081Sasomersstatic struct interface** 88261081Sasomersnhash(char *p) 89261081Sasomers{ 90261081Sasomers u_int i; 91261081Sasomers 92261081Sasomers for (i = 0; *p != '\0'; p++) { 93261081Sasomers i = ((i<<1) & 0x7fffffff) | ((i>>31) & 1); 94261081Sasomers i ^= *p; 95261081Sasomers } 96261081Sasomers return &nhash_tbl[i % NHASH_LEN]; 97261081Sasomers} 98261081Sasomers 99261081Sasomers 100261081Sasomers/* Link a new interface into the lists and hash tables. 101261081Sasomers */ 102261081Sasomersvoid 103292820Sngieif_link(struct interface *ifp) 104261081Sasomers{ 105261081Sasomers struct interface **hifp; 106261081Sasomers 107261081Sasomers ifp->int_prev = &ifnet; 108261081Sasomers ifp->int_next = ifnet; 109261081Sasomers if (ifnet != 0) 110261081Sasomers ifnet->int_prev = &ifp->int_next; 111261081Sasomers ifnet = ifp; 112261081Sasomers 113270228Sasomers hifp = AHASH(ifp->int_addr); 114270228Sasomers ifp->int_ahash_prev = hifp; 115270228Sasomers if ((ifp->int_ahash = *hifp) != 0) 116261081Sasomers (*hifp)->int_ahash_prev = &ifp->int_ahash; 117261081Sasomers *hifp = ifp; 118261081Sasomers 119261081Sasomers if (ifp->int_if_flags & IFF_BROADCAST) { 120261081Sasomers hifp = BHASH(ifp->int_brdaddr); 121262894Sasomers ifp->int_bhash_prev = hifp; 122261081Sasomers if ((ifp->int_bhash = *hifp) != 0) 123261081Sasomers (*hifp)->int_bhash_prev = &ifp->int_bhash; 124261081Sasomers *hifp = ifp; 125261081Sasomers } 126261081Sasomers 127261081Sasomers if (ifp->int_state & IS_REMOTE) { 128261081Sasomers ifp->int_rlink_prev = &remote_if; 129262894Sasomers ifp->int_rlink = remote_if; 130261081Sasomers if (remote_if != 0) 131261081Sasomers remote_if->int_rlink_prev = &ifp->int_rlink; 132261081Sasomers remote_if = ifp; 133261081Sasomers } 134261081Sasomers 135261081Sasomers hifp = nhash(ifp->int_name); 136262894Sasomers if (ifp->int_state & IS_ALIAS) { 137261081Sasomers /* put aliases on the end of the hash chain */ 138262894Sasomers while (*hifp != 0) 139261081Sasomers hifp = &(*hifp)->int_nhash; 140261081Sasomers } 141262133Sasomers ifp->int_nhash_prev = hifp; 142261081Sasomers if ((ifp->int_nhash = *hifp) != 0) 143261081Sasomers (*hifp)->int_nhash_prev = &ifp->int_nhash; 144261081Sasomers *hifp = ifp; 145261081Sasomers} 146261081Sasomers 147261081Sasomers 148261081Sasomers/* Find the interface with an address 149261081Sasomers */ 150262894Sasomersstruct interface * 151261081Sasomersifwithaddr(naddr addr, 152261081Sasomers int bcast, /* notice IFF_BROADCAST address */ 153270228Sasomers int remote) /* include IS_REMOTE interfaces */ 154270228Sasomers{ 155270228Sasomers struct interface *ifp, *possible = 0; 156261081Sasomers 157270228Sasomers remote = (remote == 0) ? IS_REMOTE : 0; 158261081Sasomers 159261081Sasomers for (ifp = *AHASH(addr); ifp; ifp = ifp->int_ahash) { 160261081Sasomers if (ifp->int_addr != addr) 161261081Sasomers continue; 162261081Sasomers if ((ifp->int_state & remote) != 0) 163261081Sasomers continue; 164261081Sasomers if ((ifp->int_state & (IS_BROKE | IS_PASSIVE)) == 0) 165261081Sasomers return ifp; 166261081Sasomers possible = ifp; 167262894Sasomers } 168261081Sasomers 169261081Sasomers if (possible || !bcast) 170261081Sasomers return possible; 171262894Sasomers 172261081Sasomers for (ifp = *BHASH(addr); ifp; ifp = ifp->int_bhash) { 173261081Sasomers if (ifp->int_brdaddr != addr) 174261081Sasomers continue; 175261081Sasomers if ((ifp->int_state & remote) != 0) 176261081Sasomers continue; 177261081Sasomers if ((ifp->int_state & (IS_BROKE | IS_PASSIVE)) == 0) 178261081Sasomers return ifp; 179261081Sasomers possible = ifp; 180261081Sasomers } 181261081Sasomers 182261081Sasomers return possible; 183261081Sasomers} 184261081Sasomers 185261081Sasomers 186261081Sasomers/* find the interface with a name 187261081Sasomers */ 188261081Sasomersstruct interface * 189261081Sasomersifwithname(char *name, /* "ec0" or whatever */ 190261081Sasomers naddr addr) /* 0 or network address */ 191261081Sasomers{ 192261081Sasomers struct interface *ifp; 193261081Sasomers 194261081Sasomers for (;;) { 195261081Sasomers for (ifp = *nhash(name); ifp != 0; ifp = ifp->int_nhash) { 196261081Sasomers /* If the network address is not specified, 197261081Sasomers * ignore any alias interfaces. Otherwise, look 198261081Sasomers * for the interface with the target name and address. 199261081Sasomers */ 200261081Sasomers if (!strcmp(ifp->int_name, name) 201261081Sasomers && ((addr == 0 && !(ifp->int_state & IS_ALIAS)) 202261081Sasomers || (ifp->int_addr == addr))) 203261081Sasomers return ifp; 204261081Sasomers } 205261081Sasomers 206261081Sasomers /* If there is no known interface, maybe there is a 207270228Sasomers * new interface. So just once look for new interfaces. 208270228Sasomers */ 209261081Sasomers if (IF_RESCAN_DELAY()) 210261081Sasomers return 0; 211262894Sasomers ifinit(); 212261081Sasomers } 213261081Sasomers} 214262894Sasomers 215261081Sasomers 216262894Sasomersstruct interface * 217261081Sasomersifwithindex(u_short index, 218261081Sasomers int rescan_ok) 219261081Sasomers{ 220261081Sasomers struct interface *ifp; 221261081Sasomers 222261081Sasomers for (;;) { 223261081Sasomers for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) { 224261081Sasomers if (ifp->int_index == index) 225261081Sasomers return ifp; 226261081Sasomers } 227261081Sasomers 228261081Sasomers /* If there is no known interface, maybe there is a 229261081Sasomers * new interface. So just once look for new interfaces. 230261081Sasomers */ 231261081Sasomers if (!rescan_ok 232261081Sasomers || IF_RESCAN_DELAY()) 233261081Sasomers return 0; 234261081Sasomers ifinit(); 235261081Sasomers } 236261081Sasomers} 237261081Sasomers 238261081Sasomers 239261081Sasomers/* Find an interface from which the specified address 240261081Sasomers * should have come from. Used for figuring out which 241261081Sasomers * interface a packet came in on. 242292820Sngie */ 243261081Sasomersstruct interface * 244261081Sasomersiflookup(naddr addr) 245261081Sasomers{ 246261081Sasomers struct interface *ifp, *maybe; 247261081Sasomers 248261081Sasomers maybe = 0; 249261081Sasomers for (;;) { 250261081Sasomers for (ifp = ifnet; ifp; ifp = ifp->int_next) { 251261081Sasomers if (ifp->int_if_flags & IFF_POINTOPOINT) { 252261081Sasomers /* finished with a match */ 253261081Sasomers if (ifp->int_dstaddr == addr) 254261081Sasomers return ifp; 255261081Sasomers 256261081Sasomers } else { 257261081Sasomers /* finished with an exact match */ 258261081Sasomers if (ifp->int_addr == addr) 259261081Sasomers return ifp; 260261081Sasomers 261261081Sasomers /* Look for the longest approximate match. 262261081Sasomers */ 263261081Sasomers if (on_net(addr, ifp->int_net, ifp->int_mask) 264261081Sasomers && (maybe == 0 265261081Sasomers || ifp->int_mask > maybe->int_mask)) 266261081Sasomers maybe = ifp; 267261081Sasomers } 268261081Sasomers } 269261081Sasomers 270261081Sasomers if (maybe != 0 271261081Sasomers || IF_RESCAN_DELAY()) 272261081Sasomers return maybe; 273261081Sasomers 274261081Sasomers /* If there is no known interface, maybe there is a 275261081Sasomers * new interface. So just once look for new interfaces. 276261081Sasomers */ 277261081Sasomers ifinit(); 278292820Sngie } 279261081Sasomers} 280261081Sasomers 281261081Sasomers 282261081Sasomers/* Return the classical netmask for an IP address. 283261081Sasomers */ 284270228Sasomersnaddr /* host byte order */ 285270228Sasomersstd_mask(naddr addr) /* network byte order */ 286261081Sasomers{ 287261081Sasomers NTOHL(addr); /* was a host, not a network */ 288261081Sasomers 289261081Sasomers if (addr == 0) /* default route has mask 0 */ 290261081Sasomers return 0; 291261081Sasomers if (IN_CLASSA(addr)) 292261081Sasomers return IN_CLASSA_NET; 293261081Sasomers if (IN_CLASSB(addr)) 294261081Sasomers return IN_CLASSB_NET; 295261081Sasomers return IN_CLASSC_NET; 296261081Sasomers} 297261081Sasomers 298261081Sasomers 299261081Sasomers/* Find the netmask that would be inferred by RIPv1 listeners 300261081Sasomers * on the given interface for a given network. 301261081Sasomers * If no interface is specified, look for the best fitting interface. 302261081Sasomers */ 303261081Sasomersnaddr 304261081Sasomersripv1_mask_net(naddr addr, /* in network byte order */ 305261081Sasomers struct interface *ifp) /* as seen on this interface */ 306261081Sasomers{ 307261081Sasomers struct r1net *r1p; 308261081Sasomers naddr mask = 0; 309261081Sasomers 310261081Sasomers if (addr == 0) /* default always has 0 mask */ 311261081Sasomers return mask; 312261081Sasomers 313261081Sasomers if (ifp != 0 && ifp->int_ripv1_mask != HOST_MASK) { 314261081Sasomers /* If the target network is that of the associated interface 315261081Sasomers * on which it arrived, then use the netmask of the interface. 316261081Sasomers */ 317261081Sasomers if (on_net(addr, ifp->int_net, ifp->int_std_mask)) 318261081Sasomers mask = ifp->int_ripv1_mask; 319261081Sasomers 320261081Sasomers } else { 321261081Sasomers /* Examine all interfaces, and if it the target seems 322261081Sasomers * to have the same network number of an interface, use the 323261081Sasomers * netmask of that interface. If there is more than one 324261081Sasomers * such interface, prefer the interface with the longest 325261081Sasomers * match. 326261081Sasomers */ 327261081Sasomers for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) { 328261081Sasomers if (on_net(addr, ifp->int_std_net, ifp->int_std_mask) 329261081Sasomers && ifp->int_ripv1_mask > mask 330261081Sasomers && ifp->int_ripv1_mask != HOST_MASK) 331261081Sasomers mask = ifp->int_ripv1_mask; 332261081Sasomers } 333261081Sasomers 334261081Sasomers } 335261081Sasomers 336292820Sngie /* check special definitions */ 337261081Sasomers if (mask == 0) { 338261081Sasomers for (r1p = r1nets; r1p != 0; r1p = r1p->r1net_next) { 339261081Sasomers if (on_net(addr, r1p->r1net_net, r1p->r1net_match) 340261081Sasomers && r1p->r1net_mask > mask) 341261081Sasomers mask = r1p->r1net_mask; 342261081Sasomers } 343262894Sasomers 344261081Sasomers /* Otherwise, make the classic A/B/C guess. 345261081Sasomers */ 346261081Sasomers if (mask == 0) 347261081Sasomers mask = std_mask(addr); 348261081Sasomers } 349261081Sasomers 350261081Sasomers return mask; 351261081Sasomers} 352261081Sasomers 353261081Sasomers 354261081Sasomersnaddr 355261081Sasomersripv1_mask_host(naddr addr, /* in network byte order */ 356261081Sasomers struct interface *ifp) /* as seen on this interface */ 357261081Sasomers{ 358261081Sasomers naddr mask = ripv1_mask_net(addr, ifp); 359261081Sasomers 360261081Sasomers 361261081Sasomers /* If the computed netmask does not mask the address, 362261081Sasomers * then assume it is a host address 363261081Sasomers */ 364261081Sasomers if ((ntohl(addr) & ~mask) != 0) 365261081Sasomers mask = HOST_MASK; 366261081Sasomers return mask; 367261081Sasomers} 368261081Sasomers 369261081Sasomers 370261081Sasomers/* See if a IP address looks reasonable as a destination 371261081Sasomers */ 372292820Sngieint /* 0=bad */ 373262867Sasomerscheck_dst(naddr addr) 374262867Sasomers{ 375262867Sasomers NTOHL(addr); 376262867Sasomers 377262867Sasomers if (IN_CLASSA(addr)) { 378261081Sasomers if (addr == 0) 379261081Sasomers return 1; /* default */ 380261081Sasomers 381261081Sasomers addr >>= IN_CLASSA_NSHIFT; 382261081Sasomers return (addr != 0 && addr != IN_LOOPBACKNET); 383261081Sasomers } 384270228Sasomers 385270228Sasomers return (IN_CLASSB(addr) || IN_CLASSC(addr)); 386261081Sasomers} 387261081Sasomers 388261081Sasomers 389261081Sasomers/* See a new interface duplicates an existing interface. 390261081Sasomers */ 391261081Sasomersstruct interface * 392261081Sasomerscheck_dup(naddr addr, /* IP address, so network byte order */ 393261081Sasomers naddr dstaddr, /* ditto */ 394261081Sasomers naddr mask, /* mask, so host byte order */ 395261081Sasomers int if_flags) 396261081Sasomers{ 397261081Sasomers struct interface *ifp; 398261081Sasomers 399261081Sasomers for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) { 400271397Sasomers if (ifp->int_mask != mask) 401270228Sasomers continue; 402261081Sasomers 403261081Sasomers if (!iff_up(ifp->int_if_flags)) 404261081Sasomers continue; 405261081Sasomers 406261081Sasomers /* The local address can only be shared with a point-to-point 407261081Sasomers * link. 408261081Sasomers */ 409261081Sasomers if (ifp->int_addr == addr 410261081Sasomers && (((if_flags|ifp->int_if_flags) & IFF_POINTOPOINT) == 0)) 411261081Sasomers return ifp; 412261081Sasomers 413261081Sasomers if (on_net(ifp->int_dstaddr, ntohl(dstaddr),mask)) 414261081Sasomers return ifp; 415261081Sasomers } 416270228Sasomers return 0; 417270228Sasomers} 418261081Sasomers 419261081Sasomers 420261081Sasomers/* See that a remote gateway is reachable. 421261081Sasomers * Note that the answer can change as real interfaces come and go. 422261081Sasomers */ 423261081Sasomersint /* 0=bad */ 424261081Sasomerscheck_remote(struct interface *ifp) 425261081Sasomers{ 426261081Sasomers struct rt_entry *rt; 427261081Sasomers 428261081Sasomers /* do not worry about other kinds */ 429261081Sasomers if (!(ifp->int_state & IS_REMOTE)) 430261081Sasomers return 1; 431270228Sasomers 432261081Sasomers rt = rtfind(ifp->int_addr); 433261081Sasomers if (rt != 0 434261081Sasomers && rt->rt_ifp != 0 435261081Sasomers &&on_net(ifp->int_addr, 436261081Sasomers rt->rt_ifp->int_net, rt->rt_ifp->int_mask)) 437261081Sasomers return 1; 438261081Sasomers 439261081Sasomers /* the gateway cannot be reached directly from one of our 440261081Sasomers * interfaces 441261081Sasomers */ 442261081Sasomers if (!(ifp->int_state & IS_BROKE)) { 443261081Sasomers msglog("unreachable gateway %s in "_PATH_GATEWAYS, 444261081Sasomers naddr_ntoa(ifp->int_addr)); 445261081Sasomers if_bad(ifp); 446261081Sasomers } 447261081Sasomers return 0; 448261081Sasomers} 449261081Sasomers 450261081Sasomers 451261081Sasomers/* Delete an interface. 452270228Sasomers */ 453261081Sasomersstatic void 454261081Sasomersifdel(struct interface *ifp) 455261081Sasomers{ 456261081Sasomers struct ip_mreq m; 457261081Sasomers struct interface *ifp1; 458261081Sasomers 459261081Sasomers 460261081Sasomers trace_if("Del", ifp); 461261081Sasomers 462261081Sasomers ifp->int_state |= IS_BROKE; 463261081Sasomers 464261081Sasomers /* unlink the interface 465261081Sasomers */ 466261081Sasomers *ifp->int_prev = ifp->int_next; 467261081Sasomers if (ifp->int_next != 0) 468261081Sasomers ifp->int_next->int_prev = ifp->int_prev; 469261081Sasomers *ifp->int_ahash_prev = ifp->int_ahash; 470261081Sasomers if (ifp->int_ahash != 0) 471261081Sasomers ifp->int_ahash->int_ahash_prev = ifp->int_ahash_prev; 472261081Sasomers *ifp->int_nhash_prev = ifp->int_nhash; 473261081Sasomers if (ifp->int_nhash != 0) 474261081Sasomers ifp->int_nhash->int_nhash_prev = ifp->int_nhash_prev; 475270228Sasomers if (ifp->int_if_flags & IFF_BROADCAST) { 476261081Sasomers *ifp->int_bhash_prev = ifp->int_bhash; 477261081Sasomers if (ifp->int_bhash != 0) 478261081Sasomers ifp->int_bhash->int_bhash_prev = ifp->int_bhash_prev; 479261081Sasomers } 480261081Sasomers if (ifp->int_state & IS_REMOTE) { 481261081Sasomers *ifp->int_rlink_prev = ifp->int_rlink; 482261081Sasomers if (ifp->int_rlink != 0) 483261081Sasomers ifp->int_rlink->int_rlink_prev = ifp->int_rlink_prev; 484261081Sasomers } 485261081Sasomers 486261081Sasomers if (!(ifp->int_state & IS_ALIAS)) { 487261081Sasomers /* delete aliases when the main interface dies 488261081Sasomers */ 489261081Sasomers for (ifp1 = ifnet; 0 != ifp1; ifp1 = ifp1->int_next) { 490261081Sasomers if (ifp1 != ifp 491261081Sasomers && !strcmp(ifp->int_name, ifp1->int_name)) 492261081Sasomers ifdel(ifp1); 493261081Sasomers } 494261081Sasomers 495261081Sasomers if ((ifp->int_if_flags & IFF_MULTICAST) 496261081Sasomers#ifdef MCAST_PPP_BUG 497261081Sasomers && !(ifp->int_if_flags & IFF_POINTOPOINT) 498261081Sasomers#endif 499261081Sasomers && rip_sock >= 0) { 500261081Sasomers m.imr_multiaddr.s_addr = htonl(INADDR_RIP_GROUP); 501261081Sasomers m.imr_interface.s_addr = ((ifp->int_if_flags 502261081Sasomers & IFF_POINTOPOINT) 503261081Sasomers ? ifp->int_dstaddr 504261081Sasomers : ifp->int_addr); 505261081Sasomers if (setsockopt(rip_sock,IPPROTO_IP,IP_DROP_MEMBERSHIP, 506261081Sasomers &m, sizeof(m)) < 0 507270228Sasomers && errno != EADDRNOTAVAIL 508270228Sasomers && !TRACEACTIONS) 509261081Sasomers LOGERR("setsockopt(IP_DROP_MEMBERSHIP RIP)"); 510261081Sasomers if (rip_sock_mcast == ifp) 511261081Sasomers rip_sock_mcast = 0; 512261081Sasomers } 513261081Sasomers if (ifp->int_rip_sock >= 0) { 514261081Sasomers (void)close(ifp->int_rip_sock); 515261081Sasomers ifp->int_rip_sock = -1; 516261081Sasomers fix_select(); 517261081Sasomers } 518270228Sasomers 519270228Sasomers tot_interfaces--; 520261081Sasomers if (!IS_RIP_OFF(ifp->int_state)) 521261081Sasomers rip_interfaces--; 522261081Sasomers 523261081Sasomers /* Zap all routes associated with this interface. 524261081Sasomers * Assume routes just using gateways beyond this interface 525261081Sasomers * will timeout naturally, and have probably already died. 526261081Sasomers */ 527261081Sasomers (void)rn_walktree(rhead, walk_bad, 0); 528261081Sasomers 529261081Sasomers set_rdisc_mg(ifp, 0); 530261081Sasomers if_bad_rdisc(ifp); 531261081Sasomers } 532261081Sasomers 533261081Sasomers free(ifp); 534261081Sasomers} 535270228Sasomers 536261081Sasomers 537261081Sasomers/* Mark an interface ill. 538261081Sasomers */ 539261081Sasomersvoid 540261081Sasomersif_sick(struct interface *ifp) 541261081Sasomers{ 542261081Sasomers if (0 == (ifp->int_state & (IS_SICK | IS_BROKE))) { 543261081Sasomers ifp->int_state |= IS_SICK; 544261081Sasomers ifp->int_act_time = NEVER; 545261081Sasomers trace_if("Chg", ifp); 546261081Sasomers 547261081Sasomers LIM_SEC(ifinit_timer, now.tv_sec+CHECK_BAD_INTERVAL); 548261081Sasomers } 549261081Sasomers} 550261081Sasomers 551261081Sasomers 552261081Sasomers/* Mark an interface dead. 553261081Sasomers */ 554261081Sasomersvoid 555261081Sasomersif_bad(struct interface *ifp) 556261081Sasomers{ 557261081Sasomers struct interface *ifp1; 558261081Sasomers 559261081Sasomers 560261081Sasomers if (ifp->int_state & IS_BROKE) 561261081Sasomers return; 562261081Sasomers 563261081Sasomers LIM_SEC(ifinit_timer, now.tv_sec+CHECK_BAD_INTERVAL); 564292820Sngie 565261081Sasomers ifp->int_state |= (IS_BROKE | IS_SICK); 566261081Sasomers ifp->int_act_time = NEVER; 567261081Sasomers ifp->int_query_time = NEVER; 568261081Sasomers ifp->int_data.ts = now.tv_sec; 569261081Sasomers 570261081Sasomers trace_if("Chg", ifp); 571261081Sasomers 572270228Sasomers if (!(ifp->int_state & IS_ALIAS)) { 573261081Sasomers for (ifp1 = ifnet; 0 != ifp1; ifp1 = ifp1->int_next) { 574261081Sasomers if (ifp1 != ifp 575261081Sasomers && !strcmp(ifp->int_name, ifp1->int_name)) 576261081Sasomers if_bad(ifp1); 577261081Sasomers } 578261081Sasomers (void)rn_walktree(rhead, walk_bad, 0); 579261081Sasomers if_bad_rdisc(ifp); 580261081Sasomers } 581261081Sasomers} 582261081Sasomers 583261081Sasomers 584261081Sasomers/* Mark an interface alive 585261081Sasomers */ 586261081Sasomersint /* 1=it was dead */ 587261081Sasomersif_ok(struct interface *ifp, 588261081Sasomers const char *type) 589261081Sasomers{ 590261081Sasomers struct interface *ifp1; 591261081Sasomers 592261081Sasomers 593261081Sasomers if (!(ifp->int_state & IS_BROKE)) { 594261081Sasomers if (ifp->int_state & IS_SICK) { 595261081Sasomers trace_act("%sinterface %s to %s working better", 596261081Sasomers type, 597261081Sasomers ifp->int_name, naddr_ntoa(ifp->int_dstaddr)); 598261081Sasomers ifp->int_state &= ~IS_SICK; 599261081Sasomers } 600261081Sasomers return 0; 601261081Sasomers } 602261081Sasomers 603261081Sasomers msglog("%sinterface %s to %s restored", 604261081Sasomers type, ifp->int_name, naddr_ntoa(ifp->int_dstaddr)); 605261081Sasomers ifp->int_state &= ~(IS_BROKE | IS_SICK); 606261081Sasomers ifp->int_data.ts = 0; 607261081Sasomers 608261081Sasomers if (!(ifp->int_state & IS_ALIAS)) { 609261081Sasomers for (ifp1 = ifnet; 0 != ifp1; ifp1 = ifp1->int_next) { 610261081Sasomers if (ifp1 != ifp 611261081Sasomers && !strcmp(ifp->int_name, ifp1->int_name)) 612261081Sasomers if_ok(ifp1, type); 613261081Sasomers } 614261081Sasomers if_ok_rdisc(ifp); 615261081Sasomers } 616261081Sasomers 617261081Sasomers if (ifp->int_state & IS_REMOTE) { 618261081Sasomers if (!addrouteforif(ifp)) 619261081Sasomers return 0; 620261081Sasomers } 621261081Sasomers return 1; 622261081Sasomers} 623261081Sasomers 624261081Sasomers 625261081Sasomers/* disassemble routing message 626261081Sasomers */ 627261081Sasomersvoid 628261081Sasomersrt_xaddrs(struct rt_addrinfo *info, 629270228Sasomers struct sockaddr *sa, 630270228Sasomers struct sockaddr *lim, 631261081Sasomers int addrs) 632261081Sasomers{ 633261081Sasomers int i; 634261081Sasomers#ifdef _HAVE_SA_LEN 635261081Sasomers static struct sockaddr sa_zero; 636261081Sasomers#endif 637261081Sasomers#ifdef sgi 638261081Sasomers#define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(__uint64_t) - 1))) \ 639261081Sasomers : sizeof(__uint64_t)) 640261081Sasomers#else 641261081Sasomers#define ROUNDUP(a) ((a) > 0 ? (1 + (((a) - 1) | (sizeof(long) - 1))) \ 642262894Sasomers : sizeof(long)) 643261081Sasomers#endif 644261081Sasomers 645261081Sasomers 646261081Sasomers memset(info, 0, sizeof(*info)); 647261081Sasomers info->rti_addrs = addrs; 648261081Sasomers for (i = 0; i < RTAX_MAX && sa < lim; i++) { 649261081Sasomers if ((addrs & (1 << i)) == 0) 650261081Sasomers continue; 651261081Sasomers#ifdef _HAVE_SA_LEN 652261081Sasomers info->rti_info[i] = (sa->sa_len != 0) ? sa : &sa_zero; 653261081Sasomers sa = (struct sockaddr *)((char*)(sa) 654261081Sasomers + ROUNDUP(sa->sa_len)); 655261081Sasomers#else 656261081Sasomers info->rti_info[i] = sa; 657261081Sasomers sa = (struct sockaddr *)((char*)(sa) 658261081Sasomers + ROUNDUP(_FAKE_SA_LEN_DST(sa))); 659261081Sasomers#endif 660270228Sasomers } 661270228Sasomers} 662261081Sasomers 663261081Sasomers 664261081Sasomers/* Find the network interfaces which have configured themselves. 665261081Sasomers * This must be done regularly, if only for extra addresses 666261081Sasomers * that come and go on interfaces. 667261081Sasomers */ 668261081Sasomersvoid 669261081Sasomersifinit(void) 670261081Sasomers{ 671261081Sasomers static char *sysctl_buf; 672261081Sasomers static size_t sysctl_buf_size = 0; 673261081Sasomers uint complaints = 0; 674292821Sngie static u_int prev_complaints = 0; 675261081Sasomers# define COMP_NOT_INET 0x001 676292821Sngie# define COMP_NOADDR 0x002 677261081Sasomers# define COMP_BADADDR 0x004 678261081Sasomers# define COMP_NODST 0x008 679261081Sasomers# define COMP_NOBADR 0x010 680261081Sasomers# define COMP_NOMASK 0x020 681261081Sasomers# define COMP_DUP 0x040 682262894Sasomers# define COMP_BAD_METRIC 0x080 683261081Sasomers# define COMP_NETMASK 0x100 684261081Sasomers 685261081Sasomers struct interface ifs, ifs0, *ifp, *ifp1; 686261081Sasomers struct rt_entry *rt; 687292821Sngie size_t needed; 688292821Sngie int mib[6]; 689292821Sngie struct if_msghdr *ifm; 690292821Sngie struct ifa_msghdr *ifam, *ifam_lim, *ifam2; 691261081Sasomers int in, ierr, out, oerr; 692261081Sasomers struct intnet *intnetp; 693261081Sasomers struct rt_addrinfo info; 694261081Sasomers#ifdef SIOCGIFMETRIC 695261081Sasomers struct ifreq ifr; 696261081Sasomers#endif 697261081Sasomers 698261081Sasomers 699261081Sasomers last_ifinit = now; 700261081Sasomers ifinit_timer.tv_sec = now.tv_sec + (supplier 701261081Sasomers ? CHECK_ACT_INTERVAL 702261081Sasomers : CHECK_QUIET_INTERVAL); 703261081Sasomers 704261081Sasomers /* mark all interfaces so we can get rid of those that disappear */ 705261081Sasomers for (ifp = ifnet; 0 != ifp; ifp = ifp->int_next) 706261081Sasomers ifp->int_state &= ~(IS_CHECKED | IS_DUP); 707261081Sasomers 708261081Sasomers /* Fetch the interface list, without too many system calls 709261081Sasomers * since we do it repeatedly. 710261081Sasomers */ 711292821Sngie mib[0] = CTL_NET; 712292820Sngie mib[1] = PF_ROUTE; 713261081Sasomers mib[2] = 0; 714261081Sasomers mib[3] = AF_INET; 715261081Sasomers mib[4] = NET_RT_IFLIST; 716261081Sasomers mib[5] = 0; 717261081Sasomers for (;;) { 718292821Sngie if ((needed = sysctl_buf_size) != 0) { 719292821Sngie if (sysctl(mib, 6, sysctl_buf,&needed, 0, 0) >= 0) 720292821Sngie break; 721270228Sasomers /* retry if the table grew */ 722270228Sasomers if (errno != ENOMEM && errno != EFAULT) 723261081Sasomers BADERR(1, "ifinit: sysctl(RT_IFLIST)"); 724261081Sasomers free(sysctl_buf); 725292820Sngie needed = 0; 726261081Sasomers } 727261081Sasomers if (sysctl(mib, 6, 0, &needed, 0, 0) < 0) 728261081Sasomers BADERR(1,"ifinit: sysctl(RT_IFLIST) estimate"); 729261081Sasomers sysctl_buf = rtmalloc(sysctl_buf_size = needed, 730261081Sasomers "ifinit sysctl"); 731261081Sasomers } 732261081Sasomers 733261081Sasomers ifam_lim = (struct ifa_msghdr *)(sysctl_buf + needed); 734261081Sasomers for (ifam = (struct ifa_msghdr *)sysctl_buf; 735261081Sasomers ifam < ifam_lim; 736262894Sasomers ifam = ifam2) { 737261081Sasomers 738261081Sasomers ifam2 = (struct ifa_msghdr*)((char*)ifam + ifam->ifam_msglen); 739261081Sasomers 740261081Sasomers if (ifam->ifam_type == RTM_IFINFO) { 741261081Sasomers struct sockaddr_dl *sdl; 742261081Sasomers 743261081Sasomers ifm = (struct if_msghdr *)ifam; 744261081Sasomers /* make prototype structure for the IP aliases 745261081Sasomers */ 746261081Sasomers memset(&ifs0, 0, sizeof(ifs0)); 747261081Sasomers ifs0.int_rip_sock = -1; 748261081Sasomers ifs0.int_index = ifm->ifm_index; 749261081Sasomers ifs0.int_if_flags = ifm->ifm_flags; 750261081Sasomers ifs0.int_state = IS_CHECKED; 751261081Sasomers ifs0.int_query_time = NEVER; 752261081Sasomers ifs0.int_act_time = now.tv_sec; 753270228Sasomers ifs0.int_data.ts = now.tv_sec; 754270228Sasomers ifs0.int_data.ipackets = ifm->ifm_data.ifi_ipackets; 755261081Sasomers ifs0.int_data.ierrors = ifm->ifm_data.ifi_ierrors; 756261081Sasomers ifs0.int_data.opackets = ifm->ifm_data.ifi_opackets; 757261081Sasomers ifs0.int_data.oerrors = ifm->ifm_data.ifi_oerrors; 758261081Sasomers#ifdef sgi 759261081Sasomers ifs0.int_data.odrops = ifm->ifm_data.ifi_odrops; 760261081Sasomers#endif 761286011Spluknet sdl = (struct sockaddr_dl *)(ifm + 1); 762286011Spluknet sdl->sdl_data[sdl->sdl_nlen] = 0; 763286011Spluknet strncpy(ifs0.int_name, sdl->sdl_data, 764286011Spluknet MIN(sizeof(ifs0.int_name), sdl->sdl_nlen)); 765261081Sasomers continue; 766286011Spluknet } 767261081Sasomers if (ifam->ifam_type != RTM_NEWADDR) { 768261081Sasomers logbad(1,"ifinit: out of sync"); 769270228Sasomers continue; 770286011Spluknet } 771286011Spluknet rt_xaddrs(&info, (struct sockaddr *)(ifam+1), 772286011Spluknet (struct sockaddr *)ifam2, 773286011Spluknet ifam->ifam_addrs); 774286011Spluknet 775286011Spluknet /* Prepare for the next address of this interface, which 776286011Spluknet * will be an alias. 777286011Spluknet * Do not output RIP or Router-Discovery packets via aliases. 778286011Spluknet */ 779286011Spluknet memcpy(&ifs, &ifs0, sizeof(ifs)); 780286011Spluknet ifs0.int_state |= (IS_ALIAS | IS_NO_RIP_OUT | IS_NO_RDISC); 781286011Spluknet 782286011Spluknet if (INFO_IFA(&info) == 0) { 783286011Spluknet if (iff_up(ifs.int_if_flags)) { 784286011Spluknet if (!(prev_complaints & COMP_NOADDR)) 785286011Spluknet msglog("%s has no address", 786286011Spluknet ifs.int_name); 787286011Spluknet complaints |= COMP_NOADDR; 788286011Spluknet } 789261081Sasomers continue; 790286011Spluknet } 791261081Sasomers if (INFO_IFA(&info)->sa_family != AF_INET) { 792261081Sasomers if (iff_up(ifs.int_if_flags)) { 793270228Sasomers if (!(prev_complaints & COMP_NOT_INET)) 794286011Spluknet trace_act("%s: not AF_INET", 795261081Sasomers ifs.int_name); 796261081Sasomers complaints |= COMP_NOT_INET; 797261081Sasomers } 798261081Sasomers continue; 799261081Sasomers } 800261081Sasomers 801286011Spluknet ifs.int_addr = S_ADDR(INFO_IFA(&info)); 802286011Spluknet 803286011Spluknet if (ntohl(ifs.int_addr)>>24 == 0 804286011Spluknet || ntohl(ifs.int_addr)>>24 == 0xff) { 805286011Spluknet if (iff_up(ifs.int_if_flags)) { 806261081Sasomers if (!(prev_complaints & COMP_BADADDR)) 807261081Sasomers msglog("%s has a bad address", 808270228Sasomers ifs.int_name); 809286011Spluknet complaints |= COMP_BADADDR; 810286011Spluknet } 811286011Spluknet continue; 812286011Spluknet } 813286011Spluknet 814286011Spluknet if (ifs.int_if_flags & IFF_LOOPBACK) { 815286011Spluknet ifs.int_state |= IS_PASSIVE | IS_NO_RIP | IS_NO_RDISC; 816286011Spluknet ifs.int_dstaddr = ifs.int_addr; 817286011Spluknet ifs.int_mask = HOST_MASK; 818286011Spluknet ifs.int_ripv1_mask = HOST_MASK; 819286011Spluknet ifs.int_std_mask = std_mask(ifs.int_dstaddr); 820286011Spluknet ifs.int_net = ntohl(ifs.int_dstaddr); 821286011Spluknet if (!foundloopback) { 822286011Spluknet foundloopback = 1; 823286011Spluknet loopaddr = ifs.int_addr; 824286011Spluknet loop_rts.rts_gate = loopaddr; 825286011Spluknet loop_rts.rts_router = loopaddr; 826286011Spluknet } 827286011Spluknet 828261081Sasomers } else if (ifs.int_if_flags & IFF_POINTOPOINT) { 829292821Sngie if (INFO_BRD(&info) == 0 830261081Sasomers || INFO_BRD(&info)->sa_family != AF_INET) { 831270228Sasomers if (iff_up(ifs.int_if_flags)) { 832286011Spluknet if (!(prev_complaints & COMP_NODST)) 833261081Sasomers msglog("%s has a bad" 834261081Sasomers " destination address", 835261081Sasomers ifs.int_name); 836261081Sasomers complaints |= COMP_NODST; 837261081Sasomers } 838261081Sasomers continue; 839261081Sasomers } 840261081Sasomers ifs.int_dstaddr = S_ADDR(INFO_BRD(&info)); 841261081Sasomers if (ntohl(ifs.int_dstaddr)>>24 == 0 842261081Sasomers || ntohl(ifs.int_dstaddr)>>24 == 0xff) { 843262894Sasomers if (iff_up(ifs.int_if_flags)) { 844261081Sasomers if (!(prev_complaints & COMP_NODST)) 845261081Sasomers msglog("%s has a bad" 846261081Sasomers " destination address", 847261081Sasomers ifs.int_name); 848261081Sasomers complaints |= COMP_NODST; 849261081Sasomers } 850261081Sasomers continue; 851261081Sasomers } 852261081Sasomers ifs.int_mask = HOST_MASK; 853261081Sasomers ifs.int_ripv1_mask = ntohl(S_ADDR(INFO_MASK(&info))); 854261081Sasomers ifs.int_std_mask = std_mask(ifs.int_dstaddr); 855261081Sasomers ifs.int_net = ntohl(ifs.int_dstaddr); 856261081Sasomers 857261081Sasomers } else { 858261081Sasomers if (INFO_MASK(&info) == 0) { 859261081Sasomers if (iff_up(ifs.int_if_flags)) { 860261081Sasomers if (!(prev_complaints & COMP_NOMASK)) 861261081Sasomers msglog("%s has no netmask", 862261081Sasomers ifs.int_name); 863261081Sasomers complaints |= COMP_NOMASK; 864261081Sasomers } 865261081Sasomers continue; 866270228Sasomers } 867270228Sasomers ifs.int_dstaddr = ifs.int_addr; 868261081Sasomers ifs.int_mask = ntohl(S_ADDR(INFO_MASK(&info))); 869261081Sasomers ifs.int_ripv1_mask = ifs.int_mask; 870292820Sngie ifs.int_std_mask = std_mask(ifs.int_addr); 871261081Sasomers ifs.int_net = ntohl(ifs.int_addr) & ifs.int_mask; 872261081Sasomers if (ifs.int_mask != ifs.int_std_mask) 873261081Sasomers ifs.int_state |= IS_SUBNET; 874261081Sasomers 875261081Sasomers if (ifs.int_if_flags & IFF_BROADCAST) { 876261081Sasomers if (INFO_BRD(&info) == 0) { 877261081Sasomers if (iff_up(ifs.int_if_flags)) { 878261081Sasomers if (!(prev_complaints 879261081Sasomers & COMP_NOBADR)) 880261081Sasomers msglog("%s has" 881261081Sasomers "no broadcast address", 882262894Sasomers ifs.int_name); 883261081Sasomers complaints |= COMP_NOBADR; 884261081Sasomers } 885261081Sasomers continue; 886261081Sasomers } 887261081Sasomers ifs.int_brdaddr = S_ADDR(INFO_BRD(&info)); 888261081Sasomers } 889261081Sasomers } 890261081Sasomers ifs.int_std_net = ifs.int_net & ifs.int_std_mask; 891261081Sasomers ifs.int_std_addr = htonl(ifs.int_std_net); 892261081Sasomers 893261081Sasomers /* Use a minimum metric of one. Treat the interface metric 894261081Sasomers * (default 0) as an increment to the hop count of one. 895270228Sasomers * 896270228Sasomers * The metric obtained from the routing socket dump of 897261081Sasomers * interface addresses is wrong. It is not set by the 898261081Sasomers * SIOCSIFMETRIC ioctl. 899292820Sngie */ 900261081Sasomers#ifdef SIOCGIFMETRIC 901261081Sasomers strncpy(ifr.ifr_name, ifs.int_name, sizeof(ifr.ifr_name)); 902261081Sasomers if (ioctl(rt_sock, SIOCGIFMETRIC, &ifr) < 0) { 903261081Sasomers DBGERR(1, "ioctl(SIOCGIFMETRIC)"); 904261081Sasomers ifs.int_metric = 0; 905261081Sasomers } else { 906261081Sasomers ifs.int_metric = ifr.ifr_metric; 907261081Sasomers } 908261081Sasomers#else 909261081Sasomers ifs.int_metric = ifam->ifam_metric; 910261081Sasomers#endif 911262894Sasomers if (ifs.int_metric > HOPCNT_INFINITY) { 912261081Sasomers ifs.int_metric = 0; 913261081Sasomers if (!(prev_complaints & COMP_BAD_METRIC) 914261081Sasomers && iff_up(ifs.int_if_flags)) { 915261081Sasomers complaints |= COMP_BAD_METRIC; 916261081Sasomers msglog("%s has a metric of %d", 917261081Sasomers ifs.int_name, ifs.int_metric); 918261081Sasomers } 919261081Sasomers } 920261081Sasomers 921261081Sasomers /* See if this is a familiar interface. 922261081Sasomers * If so, stop worrying about it if it is the same. 923261081Sasomers * Start it over if it now is to somewhere else, as happens 924270228Sasomers * frequently with PPP and SLIP. 925270228Sasomers */ 926261081Sasomers ifp = ifwithname(ifs.int_name, ((ifs.int_state & IS_ALIAS) 927261081Sasomers ? ifs.int_addr 928261081Sasomers : 0)); 929292820Sngie if (ifp != 0) { 930261081Sasomers ifp->int_state |= IS_CHECKED; 931261081Sasomers 932261081Sasomers if (0 != ((ifp->int_if_flags ^ ifs.int_if_flags) 933261081Sasomers & (IFF_BROADCAST 934261081Sasomers | IFF_LOOPBACK 935261081Sasomers | IFF_POINTOPOINT 936261081Sasomers | IFF_MULTICAST)) 937261081Sasomers || 0 != ((ifp->int_state ^ ifs.int_state) 938261081Sasomers & IS_ALIAS) 939261081Sasomers || ifp->int_addr != ifs.int_addr 940261081Sasomers || ifp->int_brdaddr != ifs.int_brdaddr 941261081Sasomers || ifp->int_dstaddr != ifs.int_dstaddr 942261081Sasomers || ifp->int_mask != ifs.int_mask 943261081Sasomers || ifp->int_metric != ifs.int_metric) { 944261081Sasomers /* Forget old information about 945261081Sasomers * a changed interface. 946261081Sasomers */ 947261081Sasomers trace_act("interface %s has changed", 948261081Sasomers ifp->int_name); 949261081Sasomers ifdel(ifp); 950261081Sasomers ifp = 0; 951261081Sasomers } 952261081Sasomers } 953261081Sasomers 954261081Sasomers if (ifp != 0) { 955292820Sngie /* The primary representative of an alias worries 956261081Sasomers * about how things are working. 957261081Sasomers */ 958261081Sasomers if (ifp->int_state & IS_ALIAS) 959261081Sasomers continue; 960261081Sasomers 961261081Sasomers /* note interfaces that have been turned off 962262894Sasomers */ 963261081Sasomers if (!iff_up(ifs.int_if_flags)) { 964264133Sjmmv if (iff_up(ifp->int_if_flags)) { 965261081Sasomers msglog("interface %s to %s turned off", 966261081Sasomers ifp->int_name, 967262894Sasomers naddr_ntoa(ifp->int_dstaddr)); 968262894Sasomers if_bad(ifp); 969261081Sasomers ifp->int_if_flags &= ~IFF_UP; 970261081Sasomers } else if (now.tv_sec>(ifp->int_data.ts 971261081Sasomers + CHECK_BAD_INTERVAL)) { 972261081Sasomers trace_act("interface %s has been off" 973261081Sasomers " %ld seconds; forget it", 974261081Sasomers ifp->int_name, 975262894Sasomers now.tv_sec-ifp->int_data.ts); 976262894Sasomers ifdel(ifp); 977262894Sasomers } 978262894Sasomers continue; 979261081Sasomers } 980292820Sngie /* or that were off and are now ok */ 981261081Sasomers if (!iff_up(ifp->int_if_flags)) { 982261081Sasomers ifp->int_if_flags |= IFF_UP; 983261081Sasomers (void)if_ok(ifp, ""); 984262894Sasomers } 985261081Sasomers 986261081Sasomers /* If it has been long enough, 987261081Sasomers * see if the interface is broken. 988261081Sasomers */ 989261081Sasomers if (now.tv_sec < ifp->int_data.ts+CHECK_BAD_INTERVAL) 990261081Sasomers continue; 991261081Sasomers 992261081Sasomers in = ifs.int_data.ipackets - ifp->int_data.ipackets; 993261081Sasomers ierr = ifs.int_data.ierrors - ifp->int_data.ierrors; 994261081Sasomers out = ifs.int_data.opackets - ifp->int_data.opackets; 995261081Sasomers oerr = ifs.int_data.oerrors - ifp->int_data.oerrors; 996261081Sasomers#ifdef sgi 997261081Sasomers /* Through at least IRIX 6.2, PPP and SLIP 998261081Sasomers * count packets dropped by the filters. 999261081Sasomers * But FDDI rings stuck non-operational count 1000261081Sasomers * dropped packets as they wait for improvement. 1001261081Sasomers */ 1002261081Sasomers if (!(ifp->int_if_flags & IFF_POINTOPOINT)) 1003261081Sasomers oerr += (ifs.int_data.odrops 1004261081Sasomers - ifp->int_data.odrops); 1005261081Sasomers#endif 1006261081Sasomers /* If the interface just awoke, restart the counters. 1007261081Sasomers */ 1008292820Sngie if (ifp->int_data.ts == 0) { 1009261081Sasomers ifp->int_data = ifs.int_data; 1010261081Sasomers continue; 1011261081Sasomers } 1012261081Sasomers ifp->int_data = ifs.int_data; 1013261081Sasomers 1014261081Sasomers /* Withhold judgment when the short error 1015261081Sasomers * counters wrap or the interface is reset. 1016270228Sasomers */ 1017270228Sasomers if (ierr < 0 || in < 0 || oerr < 0 || out < 0) { 1018261081Sasomers LIM_SEC(ifinit_timer, 1019261081Sasomers now.tv_sec+CHECK_BAD_INTERVAL); 1020292820Sngie continue; 1021261081Sasomers } 1022261081Sasomers 1023261081Sasomers /* Withhold judgement when there is no traffic 1024261081Sasomers */ 1025261081Sasomers if (in == 0 && out == 0 && ierr == 0 && oerr == 0) 1026261081Sasomers continue; 1027261081Sasomers 1028261081Sasomers /* It is bad if input or output is not working. 1029261081Sasomers * Require presistent problems before marking it dead. 1030261081Sasomers */ 1031261081Sasomers if ((in <= ierr && ierr > 0) 1032261081Sasomers || (out <= oerr && oerr > 0)) { 1033261081Sasomers if (!(ifp->int_state & IS_SICK)) { 1034261081Sasomers trace_act("interface %s to %s" 1035261081Sasomers " sick: in=%d ierr=%d" 1036261081Sasomers " out=%d oerr=%d", 1037261081Sasomers ifp->int_name, 1038261081Sasomers naddr_ntoa(ifp->int_dstaddr), 1039261081Sasomers in, ierr, out, oerr); 1040261081Sasomers if_sick(ifp); 1041261081Sasomers continue; 1042261081Sasomers } 1043261081Sasomers if (!(ifp->int_state & IS_BROKE)) { 1044261081Sasomers msglog("interface %s to %s broken:" 1045261081Sasomers " in=%d ierr=%d out=%d oerr=%d", 1046261081Sasomers ifp->int_name, 1047261081Sasomers naddr_ntoa(ifp->int_dstaddr), 1048261081Sasomers in, ierr, out, oerr); 1049261081Sasomers if_bad(ifp); 1050261081Sasomers } 1051292820Sngie continue; 1052261081Sasomers } 1053261081Sasomers 1054261081Sasomers /* otherwise, it is active and healthy 1055261081Sasomers */ 1056261081Sasomers ifp->int_act_time = now.tv_sec; 1057261081Sasomers (void)if_ok(ifp, ""); 1058261081Sasomers continue; 1059261081Sasomers } 1060261081Sasomers 1061261081Sasomers /* This is a new interface. 1062261081Sasomers * If it is dead, forget it. 1063261081Sasomers */ 1064261081Sasomers if (!iff_up(ifs.int_if_flags)) 1065261081Sasomers continue; 1066261081Sasomers 1067261081Sasomers /* If it duplicates an existing interface, 1068261081Sasomers * complain about it, mark the other one 1069261081Sasomers * duplicated, and forget this one. 1070261081Sasomers */ 1071261081Sasomers ifp = check_dup(ifs.int_addr,ifs.int_dstaddr,ifs.int_mask, 1072261081Sasomers ifs.int_if_flags); 1073261081Sasomers if (ifp != 0) { 1074261081Sasomers /* Ignore duplicates of itself, caused by having 1075261081Sasomers * IP aliases on the same network. 1076261081Sasomers */ 1077261081Sasomers if (!strcmp(ifp->int_name, ifs.int_name)) 1078261081Sasomers continue; 1079261081Sasomers 1080261081Sasomers if (!(prev_complaints & COMP_DUP)) { 1081261081Sasomers complaints |= COMP_DUP; 1082261081Sasomers msglog("%s (%s%s%s) is duplicated by" 1083261081Sasomers " %s (%s%s%s)", 1084261081Sasomers ifs.int_name, 1085261081Sasomers addrname(ifs.int_addr,ifs.int_mask,1), 1086261081Sasomers ((ifs.int_if_flags & IFF_POINTOPOINT) 1087261081Sasomers ? "-->" : ""), 1088261081Sasomers ((ifs.int_if_flags & IFF_POINTOPOINT) 1089261081Sasomers ? naddr_ntoa(ifs.int_dstaddr) : ""), 1090261081Sasomers ifp->int_name, 1091261081Sasomers addrname(ifp->int_addr,ifp->int_mask,1), 1092261081Sasomers ((ifp->int_if_flags & IFF_POINTOPOINT) 1093261081Sasomers ? "-->" : ""), 1094261081Sasomers ((ifp->int_if_flags & IFF_POINTOPOINT) 1095261081Sasomers ? naddr_ntoa(ifp->int_dstaddr) : "")); 1096261081Sasomers } 1097261081Sasomers ifp->int_state |= IS_DUP; 1098261081Sasomers continue; 1099261081Sasomers } 1100261081Sasomers 1101261081Sasomers if (0 == (ifs.int_if_flags & (IFF_POINTOPOINT | IFF_BROADCAST)) 1102261081Sasomers && !(ifs.int_state & IS_PASSIVE)) { 1103261081Sasomers trace_act("%s is neither broadcast, point-to-point," 1104261081Sasomers " nor loopback", 1105261081Sasomers ifs.int_name); 1106261081Sasomers if (!(ifs.int_state & IFF_MULTICAST)) 1107261081Sasomers ifs.int_state |= IS_NO_RDISC; 1108261081Sasomers } 1109261081Sasomers 1110261081Sasomers 1111261081Sasomers /* It is new and ok. Add it to the list of interfaces 1112261081Sasomers */ 1113261081Sasomers ifp = (struct interface *)rtmalloc(sizeof(*ifp), "ifinit ifp"); 1114261081Sasomers memcpy(ifp, &ifs, sizeof(*ifp)); 1115261081Sasomers get_parms(ifp); 1116261081Sasomers if_link(ifp); 1117261081Sasomers trace_if("Add", ifp); 1118261081Sasomers 1119261081Sasomers /* Notice likely bad netmask. 1120261081Sasomers */ 1121261081Sasomers if (!(prev_complaints & COMP_NETMASK) 1122261081Sasomers && !(ifp->int_if_flags & IFF_POINTOPOINT) 1123261081Sasomers && ifp->int_addr != RIP_DEFAULT) { 1124261081Sasomers for (ifp1 = ifnet; 0 != ifp1; ifp1 = ifp1->int_next) { 1125261081Sasomers if (ifp1->int_mask == ifp->int_mask) 1126261081Sasomers continue; 1127261081Sasomers if (ifp1->int_if_flags & IFF_POINTOPOINT) 1128261081Sasomers continue; 1129261081Sasomers if (ifp1->int_dstaddr == RIP_DEFAULT) 1130261081Sasomers continue; 1131261081Sasomers if (on_net(ifp->int_dstaddr, 1132261081Sasomers ifp1->int_net, ifp1->int_mask) 1133261081Sasomers || on_net(ifp1->int_dstaddr, 1134261081Sasomers ifp->int_net, ifp->int_mask)) { 1135261081Sasomers msglog("possible netmask problem" 1136261081Sasomers " between %s:%s and %s:%s", 1137261081Sasomers ifp->int_name, 1138261081Sasomers addrname(htonl(ifp->int_net), 1139261081Sasomers ifp->int_mask, 1), 1140261081Sasomers ifp1->int_name, 1141261081Sasomers addrname(htonl(ifp1->int_net), 1142261081Sasomers ifp1->int_mask, 1)); 1143261081Sasomers complaints |= COMP_NETMASK; 1144261081Sasomers } 1145261081Sasomers } 1146261081Sasomers } 1147261081Sasomers 1148261081Sasomers if (!(ifp->int_state & IS_ALIAS)) { 1149261081Sasomers /* Count the # of directly connected networks. 1150261081Sasomers */ 1151261081Sasomers if (!(ifp->int_if_flags & IFF_LOOPBACK)) 1152261081Sasomers tot_interfaces++; 1153261081Sasomers if (!IS_RIP_OFF(ifp->int_state)) 1154261081Sasomers rip_interfaces++; 1155261081Sasomers 1156261081Sasomers /* turn on router discovery and RIP If needed */ 1157261081Sasomers if_ok_rdisc(ifp); 1158261081Sasomers rip_on(ifp); 1159261081Sasomers } 1160261081Sasomers } 1161261081Sasomers 1162261081Sasomers /* If we are multi-homed and have at least two interfaces 1163261081Sasomers * listening to RIP, then output by default. 1164261081Sasomers */ 1165261081Sasomers if (!supplier_set && rip_interfaces > 1) 1166261081Sasomers set_supplier(); 1167261081Sasomers 1168261081Sasomers /* If we are multi-homed, optionally advertise a route to 1169261081Sasomers * our main address. 1170261081Sasomers */ 1171261081Sasomers if (advertise_mhome 1172261081Sasomers || (tot_interfaces > 1 1173261081Sasomers && mhome 1174261081Sasomers && (ifp = ifwithaddr(myaddr, 0, 0)) != 0 1175261081Sasomers && foundloopback)) { 1176261081Sasomers advertise_mhome = 1; 1177261081Sasomers rt = rtget(myaddr, HOST_MASK); 1178261081Sasomers if (rt != 0) { 1179261081Sasomers if (rt->rt_ifp != ifp 1180261081Sasomers || rt->rt_router != loopaddr) { 1181261081Sasomers rtdelete(rt); 1182261081Sasomers rt = 0; 1183261081Sasomers } else { 1184261081Sasomers loop_rts.rts_ifp = ifp; 1185261081Sasomers loop_rts.rts_metric = 0; 1186261081Sasomers loop_rts.rts_time = rt->rt_time; 1187261081Sasomers rtchange(rt, rt->rt_state | RS_MHOME, 1188261081Sasomers &loop_rts, 0); 1189261081Sasomers } 1190261081Sasomers } 1191261081Sasomers if (rt == 0) { 1192 loop_rts.rts_ifp = ifp; 1193 loop_rts.rts_metric = 0; 1194 rtadd(myaddr, HOST_MASK, RS_MHOME, &loop_rts); 1195 } 1196 } 1197 1198 for (ifp = ifnet; ifp != 0; ifp = ifp1) { 1199 ifp1 = ifp->int_next; /* because we may delete it */ 1200 1201 /* Forget any interfaces that have disappeared. 1202 */ 1203 if (!(ifp->int_state & (IS_CHECKED | IS_REMOTE))) { 1204 trace_act("interface %s has disappeared", 1205 ifp->int_name); 1206 ifdel(ifp); 1207 continue; 1208 } 1209 1210 if ((ifp->int_state & IS_BROKE) 1211 && !(ifp->int_state & IS_PASSIVE)) 1212 LIM_SEC(ifinit_timer, now.tv_sec+CHECK_BAD_INTERVAL); 1213 1214 /* If we ever have a RIPv1 interface, assume we always will. 1215 * It might come back if it ever goes away. 1216 */ 1217 if (!(ifp->int_state & IS_NO_RIPV1_OUT) && supplier) 1218 have_ripv1_out = 1; 1219 if (!(ifp->int_state & IS_NO_RIPV1_IN)) 1220 have_ripv1_in = 1; 1221 } 1222 1223 for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) { 1224 /* Ensure there is always a network route for interfaces, 1225 * after any dead interfaces have been deleted, which 1226 * might affect routes for point-to-point links. 1227 */ 1228 if (!addrouteforif(ifp)) 1229 continue; 1230 1231 /* Add routes to the local end of point-to-point interfaces 1232 * using loopback. 1233 */ 1234 if ((ifp->int_if_flags & IFF_POINTOPOINT) 1235 && !(ifp->int_state & IS_REMOTE) 1236 && foundloopback) { 1237 /* Delete any routes to the network address through 1238 * foreign routers. Remove even static routes. 1239 */ 1240 del_static(ifp->int_addr, HOST_MASK, 0, 0); 1241 rt = rtget(ifp->int_addr, HOST_MASK); 1242 if (rt != 0 && rt->rt_router != loopaddr) { 1243 rtdelete(rt); 1244 rt = 0; 1245 } 1246 if (rt != 0) { 1247 if (!(rt->rt_state & RS_LOCAL) 1248 || rt->rt_metric > ifp->int_metric) { 1249 ifp1 = ifp; 1250 } else { 1251 ifp1 = rt->rt_ifp; 1252 } 1253 loop_rts.rts_ifp = ifp1; 1254 loop_rts.rts_metric = 0; 1255 loop_rts.rts_time = rt->rt_time; 1256 rtchange(rt, ((rt->rt_state & ~RS_NET_SYN) 1257 | (RS_IF|RS_LOCAL)), 1258 &loop_rts, 0); 1259 } else { 1260 loop_rts.rts_ifp = ifp; 1261 loop_rts.rts_metric = 0; 1262 rtadd(ifp->int_addr, HOST_MASK, 1263 (RS_IF | RS_LOCAL), &loop_rts); 1264 } 1265 } 1266 } 1267 1268 /* add the authority routes */ 1269 for (intnetp = intnets; intnetp!=0; intnetp = intnetp->intnet_next) { 1270 rt = rtget(intnetp->intnet_addr, intnetp->intnet_mask); 1271 if (rt != 0 1272 && !(rt->rt_state & RS_NO_NET_SYN) 1273 && !(rt->rt_state & RS_NET_INT)) { 1274 rtdelete(rt); 1275 rt = 0; 1276 } 1277 if (rt == 0) { 1278 loop_rts.rts_ifp = 0; 1279 loop_rts.rts_metric = intnetp->intnet_metric-1; 1280 rtadd(intnetp->intnet_addr, intnetp->intnet_mask, 1281 RS_NET_SYN | RS_NET_INT, &loop_rts); 1282 } 1283 } 1284 1285 prev_complaints = complaints; 1286} 1287 1288 1289static void 1290check_net_syn(struct interface *ifp) 1291{ 1292 struct rt_entry *rt; 1293 static struct rt_spare new; 1294 1295 1296 /* Turn on the need to automatically synthesize a network route 1297 * for this interface only if we are running RIPv1 on some other 1298 * interface that is on a different class-A,B,or C network. 1299 */ 1300 if (have_ripv1_out || have_ripv1_in) { 1301 ifp->int_state |= IS_NEED_NET_SYN; 1302 rt = rtget(ifp->int_std_addr, ifp->int_std_mask); 1303 if (rt != 0 1304 && 0 == (rt->rt_state & RS_NO_NET_SYN) 1305 && (!(rt->rt_state & RS_NET_SYN) 1306 || rt->rt_metric > ifp->int_metric)) { 1307 rtdelete(rt); 1308 rt = 0; 1309 } 1310 if (rt == 0) { 1311 new.rts_ifp = ifp; 1312 new.rts_gate = ifp->int_addr; 1313 new.rts_router = ifp->int_addr; 1314 new.rts_metric = ifp->int_metric; 1315 rtadd(ifp->int_std_addr, ifp->int_std_mask, 1316 RS_NET_SYN, &new); 1317 } 1318 1319 } else { 1320 ifp->int_state &= ~IS_NEED_NET_SYN; 1321 1322 rt = rtget(ifp->int_std_addr, 1323 ifp->int_std_mask); 1324 if (rt != 0 1325 && (rt->rt_state & RS_NET_SYN) 1326 && rt->rt_ifp == ifp) 1327 rtbad_sub(rt); 1328 } 1329} 1330 1331 1332/* Add route for interface if not currently installed. 1333 * Create route to other end if a point-to-point link, 1334 * otherwise a route to this (sub)network. 1335 */ 1336int /* 0=bad interface */ 1337addrouteforif(struct interface *ifp) 1338{ 1339 struct rt_entry *rt; 1340 static struct rt_spare new; 1341 naddr dst; 1342 1343 1344 /* skip sick interfaces 1345 */ 1346 if (ifp->int_state & IS_BROKE) 1347 return 0; 1348 1349 /* If the interface on a subnet, then install a RIPv1 route to 1350 * the network as well (unless it is sick). 1351 */ 1352 if (ifp->int_state & IS_SUBNET) 1353 check_net_syn(ifp); 1354 1355 dst = (0 != (ifp->int_if_flags & (IFF_POINTOPOINT | IFF_LOOPBACK)) 1356 ? ifp->int_dstaddr 1357 : htonl(ifp->int_net)); 1358 1359 new.rts_ifp = ifp; 1360 new.rts_router = ifp->int_addr; 1361 new.rts_gate = ifp->int_addr; 1362 new.rts_metric = ifp->int_metric; 1363 new.rts_time = now.tv_sec; 1364 1365 /* If we are going to send packets to the gateway, 1366 * it must be reachable using our physical interfaces 1367 */ 1368 if ((ifp->int_state & IS_REMOTE) 1369 && !(ifp->int_state & IS_EXTERNAL) 1370 && !check_remote(ifp)) 1371 return 0; 1372 1373 /* We are finished if the correct main interface route exists. 1374 * The right route must be for the right interface, not synthesized 1375 * from a subnet, be a "gateway" or not as appropriate, and so forth. 1376 */ 1377 del_static(dst, ifp->int_mask, 0, 0); 1378 rt = rtget(dst, ifp->int_mask); 1379 if (rt != 0) { 1380 if ((rt->rt_ifp != ifp 1381 || rt->rt_router != ifp->int_addr) 1382 && (!(ifp->int_state & IS_DUP) 1383 || rt->rt_ifp == 0 1384 || (rt->rt_ifp->int_state & IS_BROKE))) { 1385 rtdelete(rt); 1386 rt = 0; 1387 } else { 1388 rtchange(rt, ((rt->rt_state | RS_IF) 1389 & ~(RS_NET_SYN | RS_LOCAL)), 1390 &new, 0); 1391 } 1392 } 1393 if (rt == 0) { 1394 if (ifp->int_transitions++ > 0) 1395 trace_act("re-install interface %s", 1396 ifp->int_name); 1397 1398 rtadd(dst, ifp->int_mask, RS_IF, &new); 1399 } 1400 1401 return 1; 1402} 1403