Home | History | Annotate | Line # | Download | only in routed
table.c revision 1.2
      1  1.2  thorpej /*	$NetBSD: table.c,v 1.2 1996/08/10 01:29:59 thorpej Exp $	*/
      2  1.2  thorpej 
      3  1.1  thorpej /*
      4  1.1  thorpej  * Copyright (c) 1983, 1988, 1993
      5  1.1  thorpej  *	The Regents of the University of California.  All rights reserved.
      6  1.1  thorpej  *
      7  1.1  thorpej  * Redistribution and use in source and binary forms, with or without
      8  1.1  thorpej  * modification, are permitted provided that the following conditions
      9  1.1  thorpej  * are met:
     10  1.1  thorpej  * 1. Redistributions of source code must retain the above copyright
     11  1.1  thorpej  *    notice, this list of conditions and the following disclaimer.
     12  1.1  thorpej  * 2. Redistributions in binary form must reproduce the above copyright
     13  1.1  thorpej  *    notice, this list of conditions and the following disclaimer in the
     14  1.1  thorpej  *    documentation and/or other materials provided with the distribution.
     15  1.1  thorpej  * 3. All advertising materials mentioning features or use of this software
     16  1.1  thorpej  *    must display the following acknowledgement:
     17  1.1  thorpej  *	This product includes software developed by the University of
     18  1.1  thorpej  *	California, Berkeley and its contributors.
     19  1.1  thorpej  * 4. Neither the name of the University nor the names of its contributors
     20  1.1  thorpej  *    may be used to endorse or promote products derived from this software
     21  1.1  thorpej  *    without specific prior written permission.
     22  1.1  thorpej  *
     23  1.1  thorpej  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     24  1.1  thorpej  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     25  1.1  thorpej  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     26  1.1  thorpej  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     27  1.1  thorpej  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     28  1.1  thorpej  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     29  1.1  thorpej  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     30  1.1  thorpej  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     31  1.1  thorpej  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     32  1.1  thorpej  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     33  1.1  thorpej  * SUCH DAMAGE.
     34  1.1  thorpej  */
     35  1.1  thorpej 
     36  1.1  thorpej #if !defined(lint) && !defined(sgi)
     37  1.2  thorpej #if 0
     38  1.1  thorpej static char sccsid[] = "@(#)tables.c	8.1 (Berkeley) 6/5/93";
     39  1.2  thorpej #else
     40  1.2  thorpej static char rcsid[] = "$NetBSD: table.c,v 1.2 1996/08/10 01:29:59 thorpej Exp $";
     41  1.2  thorpej #endif
     42  1.1  thorpej #endif /* not lint */
     43  1.1  thorpej 
     44  1.1  thorpej #include "defs.h"
     45  1.1  thorpej 
     46  1.1  thorpej static struct rt_spare *rts_better(struct rt_entry *);
     47  1.1  thorpej 
     48  1.1  thorpej struct radix_node_head *rhead;		/* root of the radix tree */
     49  1.1  thorpej 
     50  1.1  thorpej int	need_flash = 1;			/* flash update needed
     51  1.1  thorpej 					 * start =1 to suppress the 1st
     52  1.1  thorpej 					 */
     53  1.1  thorpej 
     54  1.1  thorpej struct timeval age_timer;		/* next check of old routes */
     55  1.1  thorpej struct timeval need_kern = {		/* need to update kernel table */
     56  1.1  thorpej 	EPOCH+MIN_WAITTIME-1
     57  1.1  thorpej };
     58  1.1  thorpej 
     59  1.1  thorpej int	stopint;
     60  1.1  thorpej 
     61  1.1  thorpej naddr	age_bad_gate;
     62  1.1  thorpej 
     63  1.1  thorpej 
     64  1.1  thorpej /* It is desirable to "aggregate" routes, to combine differing routes of
     65  1.1  thorpej  * the same metric and next hop into a common route with a smaller netmask
     66  1.1  thorpej  * or to suppress redundant routes, routes that add no information to
     67  1.1  thorpej  * routes with smaller netmasks.
     68  1.1  thorpej  *
     69  1.1  thorpej  * A route is redundant if and only if any and all routes with smaller
     70  1.1  thorpej  * but matching netmasks and nets are the same.  Since routes are
     71  1.1  thorpej  * kept sorted in the radix tree, redundant routes always come second.
     72  1.1  thorpej  *
     73  1.1  thorpej  * There are two kinds of aggregations.  First, two routes of the same bit
     74  1.1  thorpej  * mask and differing only in the least significant bit of the network
     75  1.1  thorpej  * number can be combined into a single route with a coarser mask.
     76  1.1  thorpej  *
     77  1.1  thorpej  * Second, a route can be suppressed in favor of another route with a more
     78  1.1  thorpej  * coarse mask provided no incompatible routes with intermediate masks
     79  1.1  thorpej  * are present.  The second kind of aggregation involves suppressing routes.
     80  1.1  thorpej  * A route must not be suppressed if an incompatible route exists with
     81  1.1  thorpej  * an intermediate mask, since the suppressed route would be covered
     82  1.1  thorpej  * by the intermediate.
     83  1.1  thorpej  *
     84  1.1  thorpej  * This code relies on the radix tree walk encountering routes
     85  1.1  thorpej  * sorted first by address, with the smallest address first.
     86  1.1  thorpej  */
     87  1.1  thorpej 
     88  1.1  thorpej struct ag_info ag_slots[NUM_AG_SLOTS], *ag_avail, *ag_corsest, *ag_finest;
     89  1.1  thorpej 
     90  1.1  thorpej /* #define DEBUG_AG */
     91  1.1  thorpej #ifdef DEBUG_AG
     92  1.1  thorpej #define CHECK_AG() {int acnt = 0; struct ag_info *cag;		\
     93  1.1  thorpej 	for (cag = ag_avail; cag != 0; cag = cag->ag_fine)	\
     94  1.1  thorpej 		acnt++;						\
     95  1.1  thorpej 	for (cag = ag_corsest; cag != 0; cag = cag->ag_fine)	\
     96  1.1  thorpej 		acnt++;						\
     97  1.1  thorpej 	if (acnt != NUM_AG_SLOTS) {				\
     98  1.1  thorpej 		(void)fflush(stderr);				\
     99  1.1  thorpej 		abort();					\
    100  1.1  thorpej 	}							\
    101  1.1  thorpej }
    102  1.1  thorpej #else
    103  1.1  thorpej #define CHECK_AG()
    104  1.1  thorpej #endif
    105  1.1  thorpej 
    106  1.1  thorpej 
    107  1.1  thorpej /* Output the contents of an aggregation table slot.
    108  1.1  thorpej  *	This function must always be immediately followed with the deletion
    109  1.1  thorpej  *	of the target slot.
    110  1.1  thorpej  */
    111  1.1  thorpej static void
    112  1.1  thorpej ag_out(struct ag_info *ag,
    113  1.1  thorpej 	 void (*out)(struct ag_info *))
    114  1.1  thorpej {
    115  1.1  thorpej 	struct ag_info *ag_cors;
    116  1.1  thorpej 	naddr bit;
    117  1.1  thorpej 
    118  1.1  thorpej 
    119  1.1  thorpej 	/* If we output both the even and odd twins, then the immediate parent,
    120  1.1  thorpej 	 * if it is present, is redundant, unless the parent manages to
    121  1.1  thorpej 	 * aggregate into something coarser.
    122  1.1  thorpej 	 * On successive calls, this code detects the even and odd twins,
    123  1.1  thorpej 	 * and marks the parent.
    124  1.1  thorpej 	 *
    125  1.1  thorpej 	 * Note that the order in which the radix tree code emits routes
    126  1.1  thorpej 	 * ensures that the twins are seen before the parent is emitted.
    127  1.1  thorpej 	 */
    128  1.1  thorpej 	ag_cors = ag->ag_cors;
    129  1.1  thorpej 	if (ag_cors != 0
    130  1.1  thorpej 	    && ag_cors->ag_mask == ag->ag_mask<<1
    131  1.1  thorpej 	    && ag_cors->ag_dst_h == (ag->ag_dst_h & ag_cors->ag_mask)) {
    132  1.1  thorpej 		ag_cors->ag_state |= ((ag_cors->ag_dst_h == ag->ag_dst_h)
    133  1.1  thorpej 				      ? AGS_REDUN0
    134  1.1  thorpej 				      : AGS_REDUN1);
    135  1.1  thorpej 	}
    136  1.1  thorpej 
    137  1.1  thorpej 	/* Skip it if this route is itself redundant.
    138  1.1  thorpej 	 *
    139  1.1  thorpej 	 * It is ok to change the contents of the slot here, since it is
    140  1.1  thorpej 	 * always deleted next.
    141  1.1  thorpej 	 */
    142  1.1  thorpej 	if (ag->ag_state & AGS_REDUN0) {
    143  1.1  thorpej 		if (ag->ag_state & AGS_REDUN1)
    144  1.1  thorpej 			return;
    145  1.1  thorpej 		bit = (-ag->ag_mask) >> 1;
    146  1.1  thorpej 		ag->ag_dst_h |= bit;
    147  1.1  thorpej 		ag->ag_mask |= bit;
    148  1.1  thorpej 
    149  1.1  thorpej 	} else if (ag->ag_state & AGS_REDUN1) {
    150  1.1  thorpej 		bit = (-ag->ag_mask) >> 1;
    151  1.1  thorpej 		ag->ag_mask |= bit;
    152  1.1  thorpej 	}
    153  1.1  thorpej 	out(ag);
    154  1.1  thorpej }
    155  1.1  thorpej 
    156  1.1  thorpej 
    157  1.1  thorpej static void
    158  1.1  thorpej ag_del(struct ag_info *ag)
    159  1.1  thorpej {
    160  1.1  thorpej 	CHECK_AG();
    161  1.1  thorpej 
    162  1.1  thorpej 	if (ag->ag_cors == 0)
    163  1.1  thorpej 		ag_corsest = ag->ag_fine;
    164  1.1  thorpej 	else
    165  1.1  thorpej 		ag->ag_cors->ag_fine = ag->ag_fine;
    166  1.1  thorpej 
    167  1.1  thorpej 	if (ag->ag_fine == 0)
    168  1.1  thorpej 		ag_finest = ag->ag_cors;
    169  1.1  thorpej 	else
    170  1.1  thorpej 		ag->ag_fine->ag_cors = ag->ag_cors;
    171  1.1  thorpej 
    172  1.1  thorpej 	ag->ag_fine = ag_avail;
    173  1.1  thorpej 	ag_avail = ag;
    174  1.1  thorpej 
    175  1.1  thorpej 	CHECK_AG();
    176  1.1  thorpej }
    177  1.1  thorpej 
    178  1.1  thorpej 
    179  1.1  thorpej /* Flush routes waiting for aggretation.
    180  1.1  thorpej  *	This must not suppress a route unless it is known that among all
    181  1.1  thorpej  *	routes with coarser masks that match it, the one with the longest
    182  1.1  thorpej  *	mask is appropriate.  This is ensured by scanning the routes
    183  1.1  thorpej  *	in lexical order, and with the most restritive mask first
    184  1.1  thorpej  *	among routes to the same destination.
    185  1.1  thorpej  */
    186  1.1  thorpej void
    187  1.1  thorpej ag_flush(naddr lim_dst_h,		/* flush routes to here */
    188  1.1  thorpej 	 naddr lim_mask,		/* matching this mask */
    189  1.1  thorpej 	 void (*out)(struct ag_info *))
    190  1.1  thorpej {
    191  1.1  thorpej 	struct ag_info *ag, *ag_cors;
    192  1.1  thorpej 	naddr dst_h;
    193  1.1  thorpej 
    194  1.1  thorpej 
    195  1.1  thorpej 	for (ag = ag_finest;
    196  1.1  thorpej 	     ag != 0 && ag->ag_mask >= lim_mask;
    197  1.1  thorpej 	     ag = ag_cors) {
    198  1.1  thorpej 		ag_cors = ag->ag_cors;
    199  1.1  thorpej 
    200  1.1  thorpej 		/* work on only the specified routes */
    201  1.1  thorpej 		dst_h = ag->ag_dst_h;
    202  1.1  thorpej 		if ((dst_h & lim_mask) != lim_dst_h)
    203  1.1  thorpej 			continue;
    204  1.1  thorpej 
    205  1.1  thorpej 		if (!(ag->ag_state & AGS_SUPPRESS))
    206  1.1  thorpej 			ag_out(ag, out);
    207  1.1  thorpej 
    208  1.1  thorpej 		else for ( ; ; ag_cors = ag_cors->ag_cors) {
    209  1.1  thorpej 			/* Look for a route that can suppress the
    210  1.1  thorpej 			 * current route */
    211  1.1  thorpej 			if (ag_cors == 0) {
    212  1.1  thorpej 				/* failed, so output it and look for
    213  1.1  thorpej 				 * another route to work on
    214  1.1  thorpej 				 */
    215  1.1  thorpej 				ag_out(ag, out);
    216  1.1  thorpej 				break;
    217  1.1  thorpej 			}
    218  1.1  thorpej 
    219  1.1  thorpej 			if ((dst_h & ag_cors->ag_mask) == ag_cors->ag_dst_h) {
    220  1.1  thorpej 				/* We found a route with a coarser mask that
    221  1.1  thorpej 				 * aggregates the current target.
    222  1.1  thorpej 				 *
    223  1.1  thorpej 				 * If it has a different next hop, it
    224  1.1  thorpej 				 * cannot replace the target, so output
    225  1.1  thorpej 				 * the target.
    226  1.1  thorpej 				 */
    227  1.1  thorpej 				if (ag->ag_gate != ag_cors->ag_gate
    228  1.1  thorpej 				    && !(ag->ag_state & AGS_FINE_GATE)
    229  1.1  thorpej 				    && !(ag_cors->ag_state & AGS_CORS_GATE)) {
    230  1.1  thorpej 					ag_out(ag, out);
    231  1.1  thorpej 					break;
    232  1.1  thorpej 				}
    233  1.1  thorpej 
    234  1.1  thorpej 				/* If the coarse route has a good enough
    235  1.1  thorpej 				 * metric, it suppresses the target.
    236  1.1  thorpej 				 */
    237  1.1  thorpej 				if (ag_cors->ag_pref <= ag->ag_pref) {
    238  1.1  thorpej 				    if (ag_cors->ag_seqno > ag->ag_seqno)
    239  1.1  thorpej 					ag_cors->ag_seqno = ag->ag_seqno;
    240  1.1  thorpej 				    if (AG_IS_REDUN(ag->ag_state)
    241  1.1  thorpej 					&& ag_cors->ag_mask==ag->ag_mask<<1) {
    242  1.1  thorpej 					if (ag_cors->ag_dst_h == dst_h)
    243  1.1  thorpej 					    ag_cors->ag_state |= AGS_REDUN0;
    244  1.1  thorpej 					else
    245  1.1  thorpej 					    ag_cors->ag_state |= AGS_REDUN1;
    246  1.1  thorpej 				    }
    247  1.1  thorpej 				    if (ag->ag_tag != ag_cors->ag_tag)
    248  1.1  thorpej 					    ag_cors->ag_tag = 0;
    249  1.1  thorpej 				    if (ag->ag_nhop != ag_cors->ag_nhop)
    250  1.1  thorpej 					    ag_cors->ag_nhop = 0;
    251  1.1  thorpej 				    break;
    252  1.1  thorpej 				}
    253  1.1  thorpej 			}
    254  1.1  thorpej 		}
    255  1.1  thorpej 
    256  1.1  thorpej 		/* That route has either been output or suppressed */
    257  1.1  thorpej 		ag_cors = ag->ag_cors;
    258  1.1  thorpej 		ag_del(ag);
    259  1.1  thorpej 	}
    260  1.1  thorpej 
    261  1.1  thorpej 	CHECK_AG();
    262  1.1  thorpej }
    263  1.1  thorpej 
    264  1.1  thorpej 
    265  1.1  thorpej /* Try to aggregate a route with previous routes.
    266  1.1  thorpej  */
    267  1.1  thorpej void
    268  1.1  thorpej ag_check(naddr	dst,
    269  1.1  thorpej 	 naddr	mask,
    270  1.1  thorpej 	 naddr	gate,
    271  1.1  thorpej 	 naddr	nhop,
    272  1.1  thorpej 	 char	metric,
    273  1.1  thorpej 	 char	pref,
    274  1.1  thorpej 	 u_int	seqno,
    275  1.1  thorpej 	 u_short tag,
    276  1.1  thorpej 	 u_short state,
    277  1.1  thorpej 	 void (*out)(struct ag_info *))	/* output using this */
    278  1.1  thorpej {
    279  1.1  thorpej 	struct ag_info *ag, *nag, *ag_cors;
    280  1.1  thorpej 	naddr xaddr;
    281  1.1  thorpej 	int x;
    282  1.1  thorpej 
    283  1.1  thorpej 	NTOHL(dst);
    284  1.1  thorpej 
    285  1.1  thorpej 	/* Punt non-contiguous subnet masks.
    286  1.1  thorpej 	 *
    287  1.1  thorpej 	 * (X & -X) contains a single bit if and only if X is a power of 2.
    288  1.1  thorpej 	 * (X + (X & -X)) == 0 if and only if X is a power of 2.
    289  1.1  thorpej 	 */
    290  1.1  thorpej 	if ((mask & -mask) + mask != 0) {
    291  1.1  thorpej 		struct ag_info nc_ag;
    292  1.1  thorpej 
    293  1.1  thorpej 		nc_ag.ag_dst_h = dst;
    294  1.1  thorpej 		nc_ag.ag_mask = mask;
    295  1.1  thorpej 		nc_ag.ag_gate = gate;
    296  1.1  thorpej 		nc_ag.ag_nhop = nhop;
    297  1.1  thorpej 		nc_ag.ag_metric = metric;
    298  1.1  thorpej 		nc_ag.ag_pref = pref;
    299  1.1  thorpej 		nc_ag.ag_tag = tag;
    300  1.1  thorpej 		nc_ag.ag_state = state;
    301  1.1  thorpej 		nc_ag.ag_seqno = seqno;
    302  1.1  thorpej 		out(&nc_ag);
    303  1.1  thorpej 		return;
    304  1.1  thorpej 	}
    305  1.1  thorpej 
    306  1.1  thorpej 	/* Search for the right slot in the aggregation table.
    307  1.1  thorpej 	 */
    308  1.1  thorpej 	ag_cors = 0;
    309  1.1  thorpej 	ag = ag_corsest;
    310  1.1  thorpej 	while (ag != 0) {
    311  1.1  thorpej 		if (ag->ag_mask >= mask)
    312  1.1  thorpej 			break;
    313  1.1  thorpej 
    314  1.1  thorpej 		/* Suppress old routes (i.e. combine with compatible routes
    315  1.1  thorpej 		 * with coarser masks) as we look for the right slot in the
    316  1.1  thorpej 		 * aggregation table for the new route.
    317  1.1  thorpej 		 * A route to an address less than the current destination
    318  1.1  thorpej 		 * will not be affected by the current route or any route
    319  1.1  thorpej 		 * seen hereafter.  That means it is safe to suppress it.
    320  1.1  thorpej 		 * This check keeps poor routes (eg. with large hop counts)
    321  1.1  thorpej 		 * from preventing suppresion of finer routes.
    322  1.1  thorpej 		 */
    323  1.1  thorpej 		if (ag_cors != 0
    324  1.1  thorpej 		    && ag->ag_dst_h < dst
    325  1.1  thorpej 		    && (ag->ag_state & AGS_SUPPRESS)
    326  1.1  thorpej 		    && ag_cors->ag_pref <= ag->ag_pref
    327  1.1  thorpej 		    && (ag->ag_dst_h & ag_cors->ag_mask) == ag_cors->ag_dst_h
    328  1.1  thorpej 		    && (ag_cors->ag_gate == ag->ag_gate
    329  1.1  thorpej 			|| (ag->ag_state & AGS_FINE_GATE)
    330  1.1  thorpej 			|| (ag_cors->ag_state & AGS_CORS_GATE))) {
    331  1.1  thorpej 			if (ag_cors->ag_seqno > ag->ag_seqno)
    332  1.1  thorpej 				ag_cors->ag_seqno = ag->ag_seqno;
    333  1.1  thorpej 			if (AG_IS_REDUN(ag->ag_state)
    334  1.1  thorpej 			    && ag_cors->ag_mask==ag->ag_mask<<1) {
    335  1.1  thorpej 				if (ag_cors->ag_dst_h == dst)
    336  1.1  thorpej 					ag_cors->ag_state |= AGS_REDUN0;
    337  1.1  thorpej 				else
    338  1.1  thorpej 					ag_cors->ag_state |= AGS_REDUN1;
    339  1.1  thorpej 			}
    340  1.1  thorpej 			if (ag->ag_tag != ag_cors->ag_tag)
    341  1.1  thorpej 				ag_cors->ag_tag = 0;
    342  1.1  thorpej 			if (ag->ag_nhop != ag_cors->ag_nhop)
    343  1.1  thorpej 				ag_cors->ag_nhop = 0;
    344  1.1  thorpej 			ag_del(ag);
    345  1.1  thorpej 			CHECK_AG();
    346  1.1  thorpej 		} else {
    347  1.1  thorpej 			ag_cors = ag;
    348  1.1  thorpej 		}
    349  1.1  thorpej 		ag = ag_cors->ag_fine;
    350  1.1  thorpej 	}
    351  1.1  thorpej 
    352  1.1  thorpej 	/* If we find the even/odd twin of the new route, and if the
    353  1.1  thorpej 	 * masks and so forth are equal, we can aggregate them.
    354  1.1  thorpej 	 * We can probably promote one of the pair.
    355  1.1  thorpej 	 *
    356  1.1  thorpej 	 * Since the routes are encountered in lexical order,
    357  1.1  thorpej 	 * the new route must be odd.  However, the second or later
    358  1.1  thorpej 	 * times around this loop, it could be the even twin promoted
    359  1.1  thorpej 	 * from the even/odd pair of twins of the finer route.
    360  1.1  thorpej 	 */
    361  1.1  thorpej 	while (ag != 0
    362  1.1  thorpej 	       && ag->ag_mask == mask
    363  1.1  thorpej 	       && ((ag->ag_dst_h ^ dst) & (mask<<1)) == 0) {
    364  1.1  thorpej 
    365  1.1  thorpej 		/* Here we know the target route and the route in the current
    366  1.1  thorpej 		 * slot have the same netmasks and differ by at most the
    367  1.1  thorpej 		 * last bit.  They are either for the same destination, or
    368  1.1  thorpej 		 * for an even/odd pair of destinations.
    369  1.1  thorpej 		 */
    370  1.1  thorpej 		if (ag->ag_dst_h == dst) {
    371  1.1  thorpej 			/* We have two routes to the same destination.
    372  1.1  thorpej 			 * Routes are encountered in lexical order, so a
    373  1.1  thorpej 			 * route is never promoted until the parent route is
    374  1.1  thorpej 			 * already present.  So we know that the new route is
    375  1.1  thorpej 			 * a promoted pair and the route already in the slot
    376  1.1  thorpej 			 * is the explicit route.
    377  1.1  thorpej 			 *
    378  1.1  thorpej 			 * Prefer the best route if their metrics differ,
    379  1.1  thorpej 			 * or the promoted one if not, following a sort
    380  1.1  thorpej 			 * of longest-match rule.
    381  1.1  thorpej 			 */
    382  1.1  thorpej 			if (pref <= ag->ag_pref) {
    383  1.1  thorpej 				ag->ag_gate = gate;
    384  1.1  thorpej 				ag->ag_nhop = nhop;
    385  1.1  thorpej 				ag->ag_tag = tag;
    386  1.1  thorpej 				ag->ag_metric = metric;
    387  1.1  thorpej 				ag->ag_pref = pref;
    388  1.1  thorpej 				x = ag->ag_state;
    389  1.1  thorpej 				ag->ag_state = state;
    390  1.1  thorpej 				state = x;
    391  1.1  thorpej 			}
    392  1.1  thorpej 
    393  1.1  thorpej 			/* The sequence number controls flash updating,
    394  1.1  thorpej 			 * and should be the smaller of the two.
    395  1.1  thorpej 			 */
    396  1.1  thorpej 			if (ag->ag_seqno > seqno)
    397  1.1  thorpej 				ag->ag_seqno = seqno;
    398  1.1  thorpej 
    399  1.1  thorpej 			/* some bits are set if they are set on either route */
    400  1.1  thorpej 			ag->ag_state |= (state & (AGS_PROMOTE_EITHER
    401  1.1  thorpej 						  | AGS_REDUN0 | AGS_REDUN1));
    402  1.1  thorpej 			return;
    403  1.1  thorpej 		}
    404  1.1  thorpej 
    405  1.1  thorpej 		/* If one of the routes can be promoted and the other can
    406  1.1  thorpej 		 * be suppressed, it may be possible to combine them or
    407  1.1  thorpej 		 * worthwhile to promote one.
    408  1.1  thorpej 		 *
    409  1.1  thorpej 		 * Note that any route that can be promoted is always
    410  1.1  thorpej 		 * marked to be eligible to be suppressed.
    411  1.1  thorpej 		 */
    412  1.1  thorpej 		if (!((state & AGS_PROMOTE)
    413  1.1  thorpej 		      && (ag->ag_state & AGS_SUPPRESS))
    414  1.1  thorpej 		    && !((ag->ag_state & AGS_PROMOTE)
    415  1.1  thorpej 			 && (state & AGS_SUPPRESS)))
    416  1.1  thorpej 			break;
    417  1.1  thorpej 
    418  1.1  thorpej 		/* A pair of even/odd twin routes can be combined
    419  1.1  thorpej 		 * if either is redundant, or if they are via the
    420  1.1  thorpej 		 * same gateway and have the same metric.
    421  1.1  thorpej 		 */
    422  1.1  thorpej 		if (AG_IS_REDUN(ag->ag_state)
    423  1.1  thorpej 		    || AG_IS_REDUN(state)
    424  1.1  thorpej 		    || (ag->ag_gate == gate
    425  1.1  thorpej 			&& ag->ag_pref == pref
    426  1.1  thorpej 			&& (state & ag->ag_state & AGS_PROMOTE) != 0)) {
    427  1.1  thorpej 
    428  1.1  thorpej 			/* We have both the even and odd pairs.
    429  1.1  thorpej 			 * Since the routes are encountered in order,
    430  1.1  thorpej 			 * the route in the slot must be the even twin.
    431  1.1  thorpej 			 *
    432  1.1  thorpej 			 * Combine and promote the pair of routes.
    433  1.1  thorpej 			 */
    434  1.1  thorpej 			if (seqno > ag->ag_seqno)
    435  1.1  thorpej 				seqno = ag->ag_seqno;
    436  1.1  thorpej 			if (!AG_IS_REDUN(state))
    437  1.1  thorpej 				state &= ~AGS_REDUN1;
    438  1.1  thorpej 			if (AG_IS_REDUN(ag->ag_state))
    439  1.1  thorpej 				state |= AGS_REDUN0;
    440  1.1  thorpej 			else
    441  1.1  thorpej 				state &= ~AGS_REDUN0;
    442  1.1  thorpej 			state |= (ag->ag_state & AGS_PROMOTE_EITHER);
    443  1.1  thorpej 			if (ag->ag_tag != tag)
    444  1.1  thorpej 				tag = 0;
    445  1.1  thorpej 			if (ag->ag_nhop != nhop)
    446  1.1  thorpej 				nhop = 0;
    447  1.1  thorpej 
    448  1.1  thorpej 			/* Get rid of the even twin that was already
    449  1.1  thorpej 			 * in the slot.
    450  1.1  thorpej 			 */
    451  1.1  thorpej 			ag_del(ag);
    452  1.1  thorpej 
    453  1.1  thorpej 		} else if (ag->ag_pref >= pref
    454  1.1  thorpej 			   && (ag->ag_state & AGS_PROMOTE)) {
    455  1.1  thorpej 			/* If we cannot combine the pair, maybe the route
    456  1.1  thorpej 			 * with the worse metric can be promoted.
    457  1.1  thorpej 			 *
    458  1.1  thorpej 			 * Promote the old, even twin, by giving its slot
    459  1.1  thorpej 			 * in the table to the new, odd twin.
    460  1.1  thorpej 			 */
    461  1.1  thorpej 			ag->ag_dst_h = dst;
    462  1.1  thorpej 
    463  1.1  thorpej 			xaddr = ag->ag_gate;
    464  1.1  thorpej 			ag->ag_gate = gate;
    465  1.1  thorpej 			gate = xaddr;
    466  1.1  thorpej 
    467  1.1  thorpej 			xaddr = ag->ag_nhop;
    468  1.1  thorpej 			ag->ag_nhop = nhop;
    469  1.1  thorpej 			nhop = xaddr;
    470  1.1  thorpej 
    471  1.1  thorpej 			x = ag->ag_tag;
    472  1.1  thorpej 			ag->ag_tag = tag;
    473  1.1  thorpej 			tag = x;
    474  1.1  thorpej 
    475  1.1  thorpej 			x = ag->ag_state;
    476  1.1  thorpej 			ag->ag_state = state;
    477  1.1  thorpej 			state = x;
    478  1.1  thorpej 			if (!AG_IS_REDUN(state))
    479  1.1  thorpej 				state &= ~AGS_REDUN0;
    480  1.1  thorpej 
    481  1.1  thorpej 			x = ag->ag_metric;
    482  1.1  thorpej 			ag->ag_metric = metric;
    483  1.1  thorpej 			metric = x;
    484  1.1  thorpej 
    485  1.1  thorpej 			x = ag->ag_pref;
    486  1.1  thorpej 			ag->ag_pref = pref;
    487  1.1  thorpej 			pref = x;
    488  1.1  thorpej 
    489  1.1  thorpej 			if (seqno >= ag->ag_seqno)
    490  1.1  thorpej 				seqno = ag->ag_seqno;
    491  1.1  thorpej 			else
    492  1.1  thorpej 				ag->ag_seqno = seqno;
    493  1.1  thorpej 
    494  1.1  thorpej 		} else {
    495  1.1  thorpej 			if (!(state & AGS_PROMOTE))
    496  1.1  thorpej 				break;	/* cannot promote either twin */
    497  1.1  thorpej 
    498  1.1  thorpej 			/* promote the new, odd twin by shaving its
    499  1.1  thorpej 			 * mask and address.
    500  1.1  thorpej 			 */
    501  1.1  thorpej 			if (seqno > ag->ag_seqno)
    502  1.1  thorpej 				seqno = ag->ag_seqno;
    503  1.1  thorpej 			else
    504  1.1  thorpej 				ag->ag_seqno = seqno;
    505  1.1  thorpej 			if (!AG_IS_REDUN(state))
    506  1.1  thorpej 				state &= ~AGS_REDUN1;
    507  1.1  thorpej 		}
    508  1.1  thorpej 
    509  1.1  thorpej 		mask <<= 1;
    510  1.1  thorpej 		dst &= mask;
    511  1.1  thorpej 
    512  1.1  thorpej 		if (ag_cors == 0) {
    513  1.1  thorpej 			ag = ag_corsest;
    514  1.1  thorpej 			break;
    515  1.1  thorpej 		}
    516  1.1  thorpej 		ag = ag_cors;
    517  1.1  thorpej 		ag_cors = ag->ag_cors;
    518  1.1  thorpej 	}
    519  1.1  thorpej 
    520  1.1  thorpej 	/* When we can no longer promote and combine routes,
    521  1.1  thorpej 	 * flush the old route in the target slot.  Also flush
    522  1.1  thorpej 	 * any finer routes that we know will never be aggregated by
    523  1.1  thorpej 	 * the new route.
    524  1.1  thorpej 	 *
    525  1.1  thorpej 	 * In case we moved toward coarser masks,
    526  1.1  thorpej 	 * get back where we belong
    527  1.1  thorpej 	 */
    528  1.1  thorpej 	if (ag != 0
    529  1.1  thorpej 	    && ag->ag_mask < mask) {
    530  1.1  thorpej 		ag_cors = ag;
    531  1.1  thorpej 		ag = ag->ag_fine;
    532  1.1  thorpej 	}
    533  1.1  thorpej 
    534  1.1  thorpej 	/* Empty the target slot
    535  1.1  thorpej 	 */
    536  1.1  thorpej 	if (ag != 0 && ag->ag_mask == mask) {
    537  1.1  thorpej 		ag_flush(ag->ag_dst_h, ag->ag_mask, out);
    538  1.1  thorpej 		ag = (ag_cors == 0) ? ag_corsest : ag_cors->ag_fine;
    539  1.1  thorpej 	}
    540  1.1  thorpej 
    541  1.1  thorpej #ifdef DEBUG_AG
    542  1.1  thorpej 	(void)fflush(stderr);
    543  1.1  thorpej 	if (ag == 0 && ag_cors != ag_finest)
    544  1.1  thorpej 		abort();
    545  1.1  thorpej 	if (ag_cors == 0 && ag != ag_corsest)
    546  1.1  thorpej 		abort();
    547  1.1  thorpej 	if (ag != 0 && ag->ag_cors != ag_cors)
    548  1.1  thorpej 		abort();
    549  1.1  thorpej 	if (ag_cors != 0 && ag_cors->ag_fine != ag)
    550  1.1  thorpej 		abort();
    551  1.1  thorpej 	CHECK_AG();
    552  1.1  thorpej #endif
    553  1.1  thorpej 
    554  1.1  thorpej 	/* Save the new route on the end of the table.
    555  1.1  thorpej 	 */
    556  1.1  thorpej 	nag = ag_avail;
    557  1.1  thorpej 	ag_avail = nag->ag_fine;
    558  1.1  thorpej 
    559  1.1  thorpej 	nag->ag_dst_h = dst;
    560  1.1  thorpej 	nag->ag_mask = mask;
    561  1.1  thorpej 	nag->ag_gate = gate;
    562  1.1  thorpej 	nag->ag_nhop = nhop;
    563  1.1  thorpej 	nag->ag_metric = metric;
    564  1.1  thorpej 	nag->ag_pref = pref;
    565  1.1  thorpej 	nag->ag_tag = tag;
    566  1.1  thorpej 	nag->ag_state = state;
    567  1.1  thorpej 	nag->ag_seqno = seqno;
    568  1.1  thorpej 
    569  1.1  thorpej 	nag->ag_fine = ag;
    570  1.1  thorpej 	if (ag != 0)
    571  1.1  thorpej 		ag->ag_cors = nag;
    572  1.1  thorpej 	else
    573  1.1  thorpej 		ag_finest = nag;
    574  1.1  thorpej 	nag->ag_cors = ag_cors;
    575  1.1  thorpej 	if (ag_cors == 0)
    576  1.1  thorpej 		ag_corsest = nag;
    577  1.1  thorpej 	else
    578  1.1  thorpej 		ag_cors->ag_fine = nag;
    579  1.1  thorpej 	CHECK_AG();
    580  1.1  thorpej }
    581  1.1  thorpej 
    582  1.1  thorpej 
    583  1.1  thorpej static char *
    584  1.1  thorpej rtm_type_name(u_char type)
    585  1.1  thorpej {
    586  1.1  thorpej 	static char *rtm_types[] = {
    587  1.1  thorpej 		"RTM_ADD",
    588  1.1  thorpej 		"RTM_DELETE",
    589  1.1  thorpej 		"RTM_CHANGE",
    590  1.1  thorpej 		"RTM_GET",
    591  1.1  thorpej 		"RTM_LOSING",
    592  1.1  thorpej 		"RTM_REDIRECT",
    593  1.1  thorpej 		"RTM_MISS",
    594  1.1  thorpej 		"RTM_LOCK",
    595  1.1  thorpej 		"RTM_OLDADD",
    596  1.1  thorpej 		"RTM_OLDDEL",
    597  1.1  thorpej 		"RTM_RESOLVE",
    598  1.1  thorpej 		"RTM_NEWADDR",
    599  1.1  thorpej 		"RTM_DELADDR",
    600  1.1  thorpej 		"RTM_IFINFO"
    601  1.1  thorpej 	};
    602  1.1  thorpej 	static char name0[10];
    603  1.1  thorpej 
    604  1.1  thorpej 
    605  1.1  thorpej 	if (type > sizeof(rtm_types)/sizeof(rtm_types[0])
    606  1.1  thorpej 	    || type == 0) {
    607  1.1  thorpej 		sprintf(name0, "RTM type %#x", type);
    608  1.1  thorpej 		return name0;
    609  1.1  thorpej 	} else {
    610  1.1  thorpej 		return rtm_types[type-1];
    611  1.1  thorpej 	}
    612  1.1  thorpej }
    613  1.1  thorpej 
    614  1.1  thorpej 
    615  1.1  thorpej /* Trim a mask in a sockaddr
    616  1.1  thorpej  *	Produce a length of 0 for an address of 0.
    617  1.1  thorpej  *	Otherwise produce the index of the first zero byte.
    618  1.1  thorpej  */
    619  1.1  thorpej void
    620  1.1  thorpej #ifdef _HAVE_SIN_LEN
    621  1.1  thorpej masktrim(struct sockaddr_in *ap)
    622  1.1  thorpej #else
    623  1.1  thorpej masktrim(struct sockaddr_in_new *ap)
    624  1.1  thorpej #endif
    625  1.1  thorpej {
    626  1.1  thorpej 	register char *cp;
    627  1.1  thorpej 
    628  1.1  thorpej 	if (ap->sin_addr.s_addr == 0) {
    629  1.1  thorpej 		ap->sin_len = 0;
    630  1.1  thorpej 		return;
    631  1.1  thorpej 	}
    632  1.1  thorpej 	cp = (char *)(&ap->sin_addr.s_addr+1);
    633  1.1  thorpej 	while (*--cp == 0)
    634  1.1  thorpej 		continue;
    635  1.1  thorpej 	ap->sin_len = cp - (char*)ap + 1;
    636  1.1  thorpej }
    637  1.1  thorpej 
    638  1.1  thorpej 
    639  1.1  thorpej /* Tell the kernel to add, delete or change a route
    640  1.1  thorpej  */
    641  1.1  thorpej static void
    642  1.1  thorpej rtioctl(int action,			/* RTM_DELETE, etc */
    643  1.1  thorpej 	naddr dst,
    644  1.1  thorpej 	naddr gate,
    645  1.1  thorpej 	naddr mask,
    646  1.1  thorpej 	int metric,
    647  1.1  thorpej 	int flags)
    648  1.1  thorpej {
    649  1.1  thorpej 	struct {
    650  1.1  thorpej 		struct rt_msghdr w_rtm;
    651  1.1  thorpej 		struct sockaddr_in w_dst;
    652  1.1  thorpej 		struct sockaddr_in w_gate;
    653  1.1  thorpej #ifdef _HAVE_SA_LEN
    654  1.1  thorpej 		struct sockaddr_in w_mask;
    655  1.1  thorpej #else
    656  1.1  thorpej 		struct sockaddr_in_new w_mask;
    657  1.1  thorpej #endif
    658  1.1  thorpej 	} w;
    659  1.1  thorpej 	long cc;
    660  1.1  thorpej 
    661  1.1  thorpej again:
    662  1.1  thorpej 	bzero(&w, sizeof(w));
    663  1.1  thorpej 	w.w_rtm.rtm_msglen = sizeof(w);
    664  1.1  thorpej 	w.w_rtm.rtm_version = RTM_VERSION;
    665  1.1  thorpej 	w.w_rtm.rtm_type = action;
    666  1.1  thorpej 	w.w_rtm.rtm_flags = flags;
    667  1.1  thorpej 	w.w_rtm.rtm_seq = ++rt_sock_seqno;
    668  1.1  thorpej 	w.w_rtm.rtm_addrs = RTA_DST|RTA_GATEWAY;
    669  1.1  thorpej 	if (metric != 0) {
    670  1.1  thorpej 		w.w_rtm.rtm_rmx.rmx_hopcount = metric;
    671  1.1  thorpej 		w.w_rtm.rtm_inits |= RTV_HOPCOUNT;
    672  1.1  thorpej 	}
    673  1.1  thorpej 	w.w_dst.sin_family = AF_INET;
    674  1.1  thorpej 	w.w_dst.sin_addr.s_addr = dst;
    675  1.1  thorpej 	w.w_gate.sin_family = AF_INET;
    676  1.1  thorpej 	w.w_gate.sin_addr.s_addr = gate;
    677  1.1  thorpej #ifdef _HAVE_SA_LEN
    678  1.1  thorpej 	w.w_dst.sin_len = sizeof(w.w_dst);
    679  1.1  thorpej 	w.w_gate.sin_len = sizeof(w.w_gate);
    680  1.1  thorpej #endif
    681  1.1  thorpej 	if (mask == HOST_MASK) {
    682  1.1  thorpej 		w.w_rtm.rtm_flags |= RTF_HOST;
    683  1.1  thorpej 		w.w_rtm.rtm_msglen -= sizeof(w.w_mask);
    684  1.1  thorpej 	} else {
    685  1.1  thorpej 		w.w_rtm.rtm_addrs |= RTA_NETMASK;
    686  1.1  thorpej 		w.w_mask.sin_addr.s_addr = htonl(mask);
    687  1.1  thorpej #ifdef _HAVE_SA_LEN
    688  1.1  thorpej 		masktrim(&w.w_mask);
    689  1.1  thorpej 		if (w.w_mask.sin_len == 0)
    690  1.1  thorpej 			w.w_mask.sin_len = sizeof(long);
    691  1.1  thorpej 		w.w_rtm.rtm_msglen -= (sizeof(w.w_mask) - w.w_mask.sin_len);
    692  1.1  thorpej #endif
    693  1.1  thorpej 	}
    694  1.1  thorpej #ifndef NO_INSTALL
    695  1.1  thorpej 	cc = write(rt_sock, &w, w.w_rtm.rtm_msglen);
    696  1.1  thorpej 	if (cc == w.w_rtm.rtm_msglen)
    697  1.1  thorpej 		return;
    698  1.1  thorpej 	if (cc < 0) {
    699  1.1  thorpej 		if (errno == ESRCH
    700  1.1  thorpej 		    && (action == RTM_CHANGE || action == RTM_DELETE)) {
    701  1.1  thorpej 			trace_act("route to %s disappeared before %s\n",
    702  1.1  thorpej 				  addrname(dst, mask, 0),
    703  1.1  thorpej 				  rtm_type_name(action));
    704  1.1  thorpej 			if (action == RTM_CHANGE) {
    705  1.1  thorpej 				action = RTM_ADD;
    706  1.1  thorpej 				goto again;
    707  1.1  thorpej 			}
    708  1.1  thorpej 			return;
    709  1.1  thorpej 		}
    710  1.1  thorpej 		msglog("write(rt_sock) %s %s --> %s: %s",
    711  1.1  thorpej 		       rtm_type_name(action),
    712  1.1  thorpej 		       addrname(dst, mask, 0), naddr_ntoa(gate),
    713  1.1  thorpej 		       strerror(errno));
    714  1.1  thorpej 	} else {
    715  1.1  thorpej 		msglog("write(rt_sock) wrote %d instead of %d",
    716  1.1  thorpej 		       cc, w.w_rtm.rtm_msglen);
    717  1.1  thorpej 	}
    718  1.1  thorpej #endif
    719  1.1  thorpej }
    720  1.1  thorpej 
    721  1.1  thorpej 
    722  1.1  thorpej #define KHASH_SIZE 71			/* should be prime */
    723  1.1  thorpej #define KHASH(a,m) khash_bins[((a) ^ (m)) % KHASH_SIZE]
    724  1.1  thorpej static struct khash {
    725  1.1  thorpej 	struct khash *k_next;
    726  1.1  thorpej 	naddr	k_dst;
    727  1.1  thorpej 	naddr	k_mask;
    728  1.1  thorpej 	naddr	k_gate;
    729  1.1  thorpej 	short	k_metric;
    730  1.1  thorpej 	u_short	k_state;
    731  1.1  thorpej #define	    KS_NEW	0x001
    732  1.1  thorpej #define	    KS_DELETE	0x002
    733  1.1  thorpej #define	    KS_ADD	0x004		/* add to the kernel */
    734  1.1  thorpej #define	    KS_CHANGE	0x008		/* tell kernel to change the route */
    735  1.1  thorpej #define	    KS_DEL_ADD	0x010		/* delete & add to change the kernel */
    736  1.1  thorpej #define	    KS_STATIC	0x020		/* Static flag in kernel */
    737  1.1  thorpej #define	    KS_GATEWAY	0x040		/* G flag in kernel */
    738  1.1  thorpej #define	    KS_DYNAMIC	0x080		/* result of redirect */
    739  1.1  thorpej #define	    KS_DELETED	0x100		/* already deleted */
    740  1.1  thorpej 	time_t	k_keep;
    741  1.1  thorpej #define	    K_KEEP_LIM	30
    742  1.1  thorpej 	time_t	k_redirect_time;
    743  1.1  thorpej } *khash_bins[KHASH_SIZE];
    744  1.1  thorpej 
    745  1.1  thorpej 
    746  1.1  thorpej static struct khash*
    747  1.1  thorpej kern_find(naddr dst, naddr mask, struct khash ***ppk)
    748  1.1  thorpej {
    749  1.1  thorpej 	struct khash *k, **pk;
    750  1.1  thorpej 
    751  1.1  thorpej 	for (pk = &KHASH(dst,mask); (k = *pk) != 0; pk = &k->k_next) {
    752  1.1  thorpej 		if (k->k_dst == dst && k->k_mask == mask)
    753  1.1  thorpej 			break;
    754  1.1  thorpej 	}
    755  1.1  thorpej 	if (ppk != 0)
    756  1.1  thorpej 		*ppk = pk;
    757  1.1  thorpej 	return k;
    758  1.1  thorpej }
    759  1.1  thorpej 
    760  1.1  thorpej 
    761  1.1  thorpej static struct khash*
    762  1.1  thorpej kern_add(naddr dst, naddr mask)
    763  1.1  thorpej {
    764  1.1  thorpej 	struct khash *k, **pk;
    765  1.1  thorpej 
    766  1.1  thorpej 	k = kern_find(dst, mask, &pk);
    767  1.1  thorpej 	if (k != 0)
    768  1.1  thorpej 		return k;
    769  1.1  thorpej 
    770  1.1  thorpej 	k = (struct khash *)malloc(sizeof(*k));
    771  1.1  thorpej 
    772  1.1  thorpej 	bzero(k, sizeof(*k));
    773  1.1  thorpej 	k->k_dst = dst;
    774  1.1  thorpej 	k->k_mask = mask;
    775  1.1  thorpej 	k->k_state = KS_NEW;
    776  1.1  thorpej 	k->k_redirect_time = now.tv_sec;
    777  1.1  thorpej 	k->k_keep = now.tv_sec;
    778  1.1  thorpej 	*pk = k;
    779  1.1  thorpej 
    780  1.1  thorpej 	return k;
    781  1.1  thorpej }
    782  1.1  thorpej 
    783  1.1  thorpej 
    784  1.1  thorpej /* If it has a non-zero metric, check that it is still in the table, not
    785  1.1  thorpej  *	having been deleted by interfaces coming and going.
    786  1.1  thorpej  */
    787  1.1  thorpej static void
    788  1.1  thorpej kern_check_static(struct khash *k,
    789  1.1  thorpej 		  struct interface *ifp)
    790  1.1  thorpej {
    791  1.1  thorpej 	struct rt_entry *rt;
    792  1.1  thorpej 	naddr int_addr;
    793  1.1  thorpej 
    794  1.1  thorpej 	if (k->k_metric == 0)
    795  1.1  thorpej 		return;
    796  1.1  thorpej 
    797  1.1  thorpej 	int_addr = (ifp != 0) ? ifp->int_addr : loopaddr;
    798  1.1  thorpej 
    799  1.1  thorpej 	rt = rtget(k->k_dst, k->k_mask);
    800  1.1  thorpej 	if (rt != 0) {
    801  1.1  thorpej 		if (!(rt->rt_state & RS_STATIC))
    802  1.1  thorpej 			rtchange(rt, rt->rt_state | RS_STATIC,
    803  1.1  thorpej 				 k->k_gate, int_addr,
    804  1.1  thorpej 				 k->k_metric, 0, ifp, now.tv_sec, 0);
    805  1.1  thorpej 	} else {
    806  1.1  thorpej 		rtadd(k->k_dst, k->k_mask, k->k_gate, int_addr,
    807  1.1  thorpej 		      k->k_metric, 0, RS_STATIC, ifp);
    808  1.1  thorpej 	}
    809  1.1  thorpej }
    810  1.1  thorpej 
    811  1.1  thorpej 
    812  1.1  thorpej /* add a route the kernel told us
    813  1.1  thorpej  */
    814  1.1  thorpej static void
    815  1.1  thorpej rtm_add(struct rt_msghdr *rtm,
    816  1.1  thorpej 	struct rt_addrinfo *info,
    817  1.1  thorpej 	time_t keep)
    818  1.1  thorpej {
    819  1.1  thorpej 	struct khash *k;
    820  1.1  thorpej 	struct interface *ifp;
    821  1.1  thorpej 	naddr mask;
    822  1.1  thorpej 
    823  1.1  thorpej 
    824  1.1  thorpej 	if (rtm->rtm_flags & RTF_HOST) {
    825  1.1  thorpej 		mask = HOST_MASK;
    826  1.1  thorpej 	} else if (INFO_MASK(info) != 0) {
    827  1.1  thorpej 		mask = ntohl(S_ADDR(INFO_MASK(info)));
    828  1.1  thorpej 	} else {
    829  1.1  thorpej 		msglog("punt %s without mask",
    830  1.1  thorpej 		       rtm_type_name(rtm->rtm_type));
    831  1.1  thorpej 		return;
    832  1.1  thorpej 	}
    833  1.1  thorpej 
    834  1.1  thorpej 	if (INFO_GATE(info) == 0
    835  1.1  thorpej 	    || INFO_GATE(info)->sa_family != AF_INET) {
    836  1.1  thorpej 		msglog("punt %s without gateway",
    837  1.1  thorpej 		       rtm_type_name(rtm->rtm_type));
    838  1.1  thorpej 		return;
    839  1.1  thorpej 	}
    840  1.1  thorpej 
    841  1.1  thorpej 	k = kern_add(S_ADDR(INFO_DST(info)), mask);
    842  1.1  thorpej 	if (k->k_state & KS_NEW)
    843  1.1  thorpej 		k->k_keep = now.tv_sec+keep;
    844  1.1  thorpej 	k->k_gate = S_ADDR(INFO_GATE(info));
    845  1.1  thorpej 	k->k_metric = rtm->rtm_rmx.rmx_hopcount;
    846  1.1  thorpej 	if (k->k_metric < 0)
    847  1.1  thorpej 		k->k_metric = 0;
    848  1.1  thorpej 	else if (k->k_metric > HOPCNT_INFINITY)
    849  1.1  thorpej 		 k->k_metric = HOPCNT_INFINITY;
    850  1.1  thorpej 	k->k_state &= ~(KS_DELETED | KS_GATEWAY | KS_STATIC | KS_NEW);
    851  1.1  thorpej 	if (rtm->rtm_flags & RTF_GATEWAY)
    852  1.1  thorpej 		k->k_state |= KS_GATEWAY;
    853  1.1  thorpej 	if (rtm->rtm_flags & RTF_STATIC)
    854  1.1  thorpej 		k->k_state |= KS_STATIC;
    855  1.1  thorpej 	if (rtm->rtm_flags & RTF_DYNAMIC) {
    856  1.1  thorpej 		k->k_state |= KS_DYNAMIC;
    857  1.1  thorpej 		k->k_redirect_time = now.tv_sec;
    858  1.1  thorpej 		/* Routers are not supposed to listen to redirects,
    859  1.1  thorpej 		 * so delete it.
    860  1.1  thorpej 		 */
    861  1.1  thorpej 		if (supplier) {
    862  1.1  thorpej 			k->k_keep = now.tv_sec;
    863  1.1  thorpej 			trace_act("mark redirected %s --> %s for deletion"
    864  1.1  thorpej 				  "since this is a router\n",
    865  1.1  thorpej 				  addrname(k->k_dst, k->k_mask, 0),
    866  1.1  thorpej 				  naddr_ntoa(k->k_gate));
    867  1.1  thorpej 		}
    868  1.1  thorpej 	}
    869  1.1  thorpej 
    870  1.1  thorpej 	/* If it is not a static route, quite until it is time to delete it.
    871  1.1  thorpej 	 */
    872  1.1  thorpej 	if (!(k->k_state & KS_STATIC)) {
    873  1.1  thorpej 		k->k_state |= KS_DELETE;
    874  1.1  thorpej 		LIM_SEC(need_kern, k->k_keep);
    875  1.1  thorpej 		return;
    876  1.1  thorpej 	}
    877  1.1  thorpej 
    878  1.1  thorpej 	/* Put static routes with real metrics into the daemon table so
    879  1.1  thorpej 	 * they can be advertised.
    880  1.1  thorpej 	 *
    881  1.1  thorpej 	 * Find the interface concerned
    882  1.1  thorpej 	 */
    883  1.1  thorpej 	ifp = iflookup(k->k_gate);
    884  1.1  thorpej 	if (ifp == 0) {
    885  1.1  thorpej 		/* if there is no interface, maybe it is new
    886  1.1  thorpej 		 */
    887  1.1  thorpej 		ifinit();
    888  1.1  thorpej 		ifp = iflookup(k->k_gate);
    889  1.1  thorpej 		if (ifp == 0)
    890  1.1  thorpej 			msglog("static route %s --> %s impossibly lacks ifp",
    891  1.1  thorpej 			       addrname(S_ADDR(INFO_DST(info)), mask, 0),
    892  1.1  thorpej 			       naddr_ntoa(k->k_gate));
    893  1.1  thorpej 	}
    894  1.1  thorpej 
    895  1.1  thorpej 	kern_check_static(k, ifp);
    896  1.1  thorpej }
    897  1.1  thorpej 
    898  1.1  thorpej 
    899  1.1  thorpej /* deal with packet loss
    900  1.1  thorpej  */
    901  1.1  thorpej static void
    902  1.1  thorpej rtm_lose(struct rt_msghdr *rtm,
    903  1.1  thorpej 	 struct rt_addrinfo *info)
    904  1.1  thorpej {
    905  1.1  thorpej 	if (INFO_GATE(info) == 0
    906  1.1  thorpej 	    || INFO_GATE(info)->sa_family != AF_INET) {
    907  1.1  thorpej 		msglog("punt %s without gateway",
    908  1.1  thorpej 		       rtm_type_name(rtm->rtm_type));
    909  1.1  thorpej 		return;
    910  1.1  thorpej 	}
    911  1.1  thorpej 
    912  1.1  thorpej 	if (!supplier)
    913  1.1  thorpej 		rdisc_age(S_ADDR(INFO_GATE(info)));
    914  1.1  thorpej 
    915  1.1  thorpej 	age(S_ADDR(INFO_GATE(info)));
    916  1.1  thorpej }
    917  1.1  thorpej 
    918  1.1  thorpej 
    919  1.1  thorpej /* Clean the kernel table by copying it to the daemon image.
    920  1.1  thorpej  * Eventually the daemon will delete any extra routes.
    921  1.1  thorpej  */
    922  1.1  thorpej void
    923  1.1  thorpej flush_kern(void)
    924  1.1  thorpej {
    925  1.1  thorpej 	size_t needed;
    926  1.1  thorpej 	int mib[6];
    927  1.1  thorpej 	char *buf, *next, *lim;
    928  1.1  thorpej 	struct rt_msghdr *rtm;
    929  1.1  thorpej 	struct interface *ifp;
    930  1.1  thorpej 	static struct sockaddr_in gate_sa;
    931  1.1  thorpej 	struct rt_addrinfo info;
    932  1.1  thorpej 
    933  1.1  thorpej 
    934  1.1  thorpej 	mib[0] = CTL_NET;
    935  1.1  thorpej 	mib[1] = PF_ROUTE;
    936  1.1  thorpej 	mib[2] = 0;		/* protocol */
    937  1.1  thorpej 	mib[3] = 0;		/* wildcard address family */
    938  1.1  thorpej 	mib[4] = NET_RT_DUMP;
    939  1.1  thorpej 	mib[5] = 0;		/* no flags */
    940  1.1  thorpej 	if (sysctl(mib, 6, 0, &needed, 0, 0) < 0) {
    941  1.1  thorpej 		DBGERR(1,"RT_DUMP-sysctl-estimate");
    942  1.1  thorpej 		return;
    943  1.1  thorpej 	}
    944  1.1  thorpej 	buf = malloc(needed);
    945  1.1  thorpej 	if (sysctl(mib, 6, buf, &needed, 0, 0) < 0)
    946  1.1  thorpej 		BADERR(1,"RT_DUMP");
    947  1.1  thorpej 	lim = buf + needed;
    948  1.1  thorpej 	for (next = buf; next < lim; next += rtm->rtm_msglen) {
    949  1.1  thorpej 		rtm = (struct rt_msghdr *)next;
    950  1.1  thorpej 
    951  1.1  thorpej 		rt_xaddrs(&info,
    952  1.1  thorpej 			  (struct sockaddr *)(rtm+1),
    953  1.1  thorpej 			  (struct sockaddr *)(next + rtm->rtm_msglen),
    954  1.1  thorpej 			  rtm->rtm_addrs);
    955  1.1  thorpej 
    956  1.1  thorpej 		if (INFO_DST(&info) == 0
    957  1.1  thorpej 		    || INFO_DST(&info)->sa_family != AF_INET)
    958  1.1  thorpej 			continue;
    959  1.1  thorpej 
    960  1.1  thorpej 		/* ignore ARP table entries on systems with a merged route
    961  1.1  thorpej 		 * and ARP table.
    962  1.1  thorpej 		 */
    963  1.1  thorpej 		if (rtm->rtm_flags & RTF_LLINFO)
    964  1.1  thorpej 			continue;
    965  1.1  thorpej 
    966  1.1  thorpej 		if (INFO_GATE(&info) == 0)
    967  1.1  thorpej 			continue;
    968  1.1  thorpej 		if (INFO_GATE(&info)->sa_family != AF_INET) {
    969  1.1  thorpej 			if (INFO_GATE(&info)->sa_family != AF_LINK)
    970  1.1  thorpej 				continue;
    971  1.1  thorpej 			ifp = ifwithindex(((struct sockaddr_dl *)
    972  1.1  thorpej 					   INFO_GATE(&info))->sdl_index);
    973  1.1  thorpej 			if (ifp == 0)
    974  1.1  thorpej 				continue;
    975  1.1  thorpej 			if ((ifp->int_if_flags & IFF_POINTOPOINT)
    976  1.1  thorpej 			    || S_ADDR(INFO_DST(&info)) == ifp->int_addr)
    977  1.1  thorpej 				gate_sa.sin_addr.s_addr = ifp->int_addr;
    978  1.1  thorpej 			else
    979  1.1  thorpej 				gate_sa.sin_addr.s_addr = htonl(ifp->int_net);
    980  1.1  thorpej #ifdef _HAVE_SA_LEN
    981  1.1  thorpej 			gate_sa.sin_len = sizeof(gate_sa);
    982  1.1  thorpej #endif
    983  1.1  thorpej 			gate_sa.sin_family = AF_INET;
    984  1.1  thorpej 			INFO_GATE(&info) = (struct sockaddr *)&gate_sa;
    985  1.1  thorpej 		}
    986  1.1  thorpej 
    987  1.1  thorpej 		/* ignore multicast addresses
    988  1.1  thorpej 		 */
    989  1.1  thorpej 		if (IN_MULTICAST(ntohl(S_ADDR(INFO_DST(&info)))))
    990  1.1  thorpej 			continue;
    991  1.1  thorpej 
    992  1.1  thorpej 		/* Note static routes and interface routes, and also
    993  1.1  thorpej 		 * preload the image of the kernel table so that
    994  1.1  thorpej 		 * we can later clean it, as well as avoid making
    995  1.1  thorpej 		 * unneeded changes.  Keep the old kernel routes for a
    996  1.1  thorpej 		 * few seconds to allow a RIP or router-discovery
    997  1.1  thorpej 		 * response to be heard.
    998  1.1  thorpej 		 */
    999  1.1  thorpej 		rtm_add(rtm,&info,MIN_WAITTIME);
   1000  1.1  thorpej 	}
   1001  1.1  thorpej 	free(buf);
   1002  1.1  thorpej }
   1003  1.1  thorpej 
   1004  1.1  thorpej 
   1005  1.1  thorpej /* Listen to announcements from the kernel
   1006  1.1  thorpej  */
   1007  1.1  thorpej void
   1008  1.1  thorpej read_rt(void)
   1009  1.1  thorpej {
   1010  1.1  thorpej 	long cc;
   1011  1.1  thorpej 	struct interface *ifp;
   1012  1.1  thorpej 	naddr mask;
   1013  1.1  thorpej 	union {
   1014  1.1  thorpej 		struct {
   1015  1.1  thorpej 			struct rt_msghdr rtm;
   1016  1.1  thorpej 			struct sockaddr addrs[RTAX_MAX];
   1017  1.1  thorpej 		} r;
   1018  1.1  thorpej 		struct if_msghdr ifm;
   1019  1.1  thorpej 	} m;
   1020  1.1  thorpej 	char str[100], *strp;
   1021  1.1  thorpej 	struct rt_addrinfo info;
   1022  1.1  thorpej 
   1023  1.1  thorpej 
   1024  1.1  thorpej 	for (;;) {
   1025  1.1  thorpej 		cc = read(rt_sock, &m, sizeof(m));
   1026  1.1  thorpej 		if (cc <= 0) {
   1027  1.1  thorpej 			if (cc < 0 && errno != EWOULDBLOCK)
   1028  1.1  thorpej 				LOGERR("read(rt_sock)");
   1029  1.1  thorpej 			return;
   1030  1.1  thorpej 		}
   1031  1.1  thorpej 
   1032  1.1  thorpej 		if (m.r.rtm.rtm_version != RTM_VERSION) {
   1033  1.1  thorpej 			msglog("bogus routing message version %d",
   1034  1.1  thorpej 			       m.r.rtm.rtm_version);
   1035  1.1  thorpej 			continue;
   1036  1.1  thorpej 		}
   1037  1.1  thorpej 
   1038  1.1  thorpej 		/* Ignore our own results.
   1039  1.1  thorpej 		 */
   1040  1.1  thorpej 		if (m.r.rtm.rtm_type <= RTM_CHANGE
   1041  1.1  thorpej 		    && m.r.rtm.rtm_pid == mypid) {
   1042  1.1  thorpej 			static int complained = 0;
   1043  1.1  thorpej 			if (!complained) {
   1044  1.1  thorpej 				msglog("receiving our own change messages");
   1045  1.1  thorpej 				complained = 1;
   1046  1.1  thorpej 			}
   1047  1.1  thorpej 			continue;
   1048  1.1  thorpej 		}
   1049  1.1  thorpej 
   1050  1.1  thorpej 		if (m.r.rtm.rtm_type == RTM_IFINFO
   1051  1.1  thorpej 		    || m.r.rtm.rtm_type == RTM_NEWADDR
   1052  1.1  thorpej 		    || m.r.rtm.rtm_type == RTM_DELADDR) {
   1053  1.1  thorpej 			ifp = ifwithindex(m.ifm.ifm_index);
   1054  1.1  thorpej 			if (ifp == 0)
   1055  1.1  thorpej 				trace_act("note %s with flags %#x"
   1056  1.1  thorpej 					  " for index #%d\n",
   1057  1.1  thorpej 					  rtm_type_name(m.r.rtm.rtm_type),
   1058  1.1  thorpej 					  m.ifm.ifm_flags,
   1059  1.1  thorpej 					  m.ifm.ifm_index);
   1060  1.1  thorpej 			else
   1061  1.1  thorpej 				trace_act("note %s with flags %#x for %s\n",
   1062  1.1  thorpej 					  rtm_type_name(m.r.rtm.rtm_type),
   1063  1.1  thorpej 					  m.ifm.ifm_flags,
   1064  1.1  thorpej 					  ifp->int_name);
   1065  1.1  thorpej 
   1066  1.1  thorpej 			/* After being informed of a change to an interface,
   1067  1.1  thorpej 			 * check them all now if the check would otherwise
   1068  1.1  thorpej 			 * be a long time from now, if the interface is
   1069  1.1  thorpej 			 * not known, or if the interface has been turned
   1070  1.1  thorpej 			 * off or on.
   1071  1.1  thorpej 			 */
   1072  1.1  thorpej 			if (ifinit_timer.tv_sec-now.tv_sec>=CHECK_BAD_INTERVAL
   1073  1.1  thorpej 			    || ifp == 0
   1074  1.1  thorpej 			    || ((ifp->int_if_flags ^ m.ifm.ifm_flags)
   1075  1.1  thorpej 				& IFF_UP_RUNNING) != 0)
   1076  1.1  thorpej 				ifinit_timer.tv_sec = now.tv_sec;
   1077  1.1  thorpej 			continue;
   1078  1.1  thorpej 		}
   1079  1.1  thorpej 
   1080  1.1  thorpej 		strcpy(str, rtm_type_name(m.r.rtm.rtm_type));
   1081  1.1  thorpej 		strp = &str[strlen(str)];
   1082  1.1  thorpej 		if (m.r.rtm.rtm_type <= RTM_CHANGE)
   1083  1.1  thorpej 			strp += sprintf(strp," from pid %d",m.r.rtm.rtm_pid);
   1084  1.1  thorpej 
   1085  1.1  thorpej 		rt_xaddrs(&info, m.r.addrs, &m.r.addrs[RTAX_MAX],
   1086  1.1  thorpej 			  m.r.rtm.rtm_addrs);
   1087  1.1  thorpej 
   1088  1.1  thorpej 		if (INFO_DST(&info) == 0) {
   1089  1.1  thorpej 			trace_act("ignore %s without dst\n", str);
   1090  1.1  thorpej 			continue;
   1091  1.1  thorpej 		}
   1092  1.1  thorpej 
   1093  1.1  thorpej 		if (INFO_DST(&info)->sa_family != AF_INET) {
   1094  1.1  thorpej 			trace_act("ignore %s for AF %d\n", str,
   1095  1.1  thorpej 				  INFO_DST(&info)->sa_family);
   1096  1.1  thorpej 			continue;
   1097  1.1  thorpej 		}
   1098  1.1  thorpej 
   1099  1.1  thorpej 		mask = ((INFO_MASK(&info) != 0)
   1100  1.1  thorpej 			? ntohl(S_ADDR(INFO_MASK(&info)))
   1101  1.1  thorpej 			: (m.r.rtm.rtm_flags & RTF_HOST)
   1102  1.1  thorpej 			? HOST_MASK
   1103  1.1  thorpej 			: std_mask(S_ADDR(INFO_DST(&info))));
   1104  1.1  thorpej 
   1105  1.1  thorpej 		strp += sprintf(strp, ": %s",
   1106  1.1  thorpej 				addrname(S_ADDR(INFO_DST(&info)), mask, 0));
   1107  1.1  thorpej 
   1108  1.1  thorpej 		if (IN_MULTICAST(ntohl(S_ADDR(INFO_DST(&info))))) {
   1109  1.1  thorpej 			trace_act("ignore %s for multicast %s\n", str);
   1110  1.1  thorpej 			continue;
   1111  1.1  thorpej 		}
   1112  1.1  thorpej 
   1113  1.1  thorpej 		if (INFO_GATE(&info) != 0
   1114  1.1  thorpej 		    && INFO_GATE(&info)->sa_family == AF_INET)
   1115  1.1  thorpej 			strp += sprintf(strp, " --> %s",
   1116  1.1  thorpej 					saddr_ntoa(INFO_GATE(&info)));
   1117  1.1  thorpej 
   1118  1.1  thorpej 		if (INFO_AUTHOR(&info) != 0)
   1119  1.1  thorpej 			strp += sprintf(strp, " by authority of %s",
   1120  1.1  thorpej 					saddr_ntoa(INFO_AUTHOR(&info)));
   1121  1.1  thorpej 
   1122  1.1  thorpej 		switch (m.r.rtm.rtm_type) {
   1123  1.1  thorpej 		case RTM_ADD:
   1124  1.1  thorpej 		case RTM_CHANGE:
   1125  1.1  thorpej 		case RTM_REDIRECT:
   1126  1.1  thorpej 			if (m.r.rtm.rtm_errno != 0) {
   1127  1.1  thorpej 				trace_act("ignore %s with \"%s\" error\n",
   1128  1.1  thorpej 					  str, strerror(m.r.rtm.rtm_errno));
   1129  1.1  thorpej 			} else {
   1130  1.1  thorpej 				trace_act("%s\n", str);
   1131  1.1  thorpej 				rtm_add(&m.r.rtm,&info,0);
   1132  1.1  thorpej 			}
   1133  1.1  thorpej 			break;
   1134  1.1  thorpej 
   1135  1.1  thorpej 		case RTM_DELETE:
   1136  1.1  thorpej 			if (m.r.rtm.rtm_errno != 0) {
   1137  1.1  thorpej 				trace_act("ignore %s with \"%s\" error\n",
   1138  1.1  thorpej 					  str, strerror(m.r.rtm.rtm_errno));
   1139  1.1  thorpej 			} else {
   1140  1.1  thorpej 				trace_act("%s\n", str);
   1141  1.1  thorpej 				del_static(S_ADDR(INFO_DST(&info)), mask, 1);
   1142  1.1  thorpej 			}
   1143  1.1  thorpej 			break;
   1144  1.1  thorpej 
   1145  1.1  thorpej 		case RTM_LOSING:
   1146  1.1  thorpej 			trace_act("%s\n", str);
   1147  1.1  thorpej 			rtm_lose(&m.r.rtm,&info);
   1148  1.1  thorpej 			break;
   1149  1.1  thorpej 
   1150  1.1  thorpej 		default:
   1151  1.1  thorpej 			trace_act("ignore %s\n", str);
   1152  1.1  thorpej 			break;
   1153  1.1  thorpej 		}
   1154  1.1  thorpej 	}
   1155  1.1  thorpej }
   1156  1.1  thorpej 
   1157  1.1  thorpej 
   1158  1.1  thorpej /* after aggregating, note routes that belong in the kernel
   1159  1.1  thorpej  */
   1160  1.1  thorpej static void
   1161  1.1  thorpej kern_out(struct ag_info *ag)
   1162  1.1  thorpej {
   1163  1.1  thorpej 	struct khash *k;
   1164  1.1  thorpej 
   1165  1.1  thorpej 
   1166  1.1  thorpej 	/* Do not install bad routes if they are not already present.
   1167  1.1  thorpej 	 * This includes routes that had RS_NET_SYN for interfaces that
   1168  1.1  thorpej 	 * recently died.
   1169  1.1  thorpej 	 */
   1170  1.1  thorpej 	if (ag->ag_metric == HOPCNT_INFINITY) {
   1171  1.1  thorpej 		k = kern_find(htonl(ag->ag_dst_h), ag->ag_mask, 0);
   1172  1.1  thorpej 		if (k == 0)
   1173  1.1  thorpej 			return;
   1174  1.1  thorpej 	} else {
   1175  1.1  thorpej 		k = kern_add(htonl(ag->ag_dst_h), ag->ag_mask);
   1176  1.1  thorpej 	}
   1177  1.1  thorpej 
   1178  1.1  thorpej 	if (k->k_state & KS_NEW) {
   1179  1.1  thorpej 		/* will need to add new entry to the kernel table */
   1180  1.1  thorpej 		k->k_state = KS_ADD;
   1181  1.1  thorpej 		if (ag->ag_state & AGS_GATEWAY)
   1182  1.1  thorpej 			k->k_state |= KS_GATEWAY;
   1183  1.1  thorpej 		k->k_gate = ag->ag_gate;
   1184  1.1  thorpej 		k->k_metric = ag->ag_metric;
   1185  1.1  thorpej 		return;
   1186  1.1  thorpej 	}
   1187  1.1  thorpej 
   1188  1.1  thorpej 	if (k->k_state & KS_STATIC)
   1189  1.1  thorpej 		return;
   1190  1.1  thorpej 
   1191  1.1  thorpej 	/* modify existing kernel entry if necessary */
   1192  1.1  thorpej 	if (k->k_gate != ag->ag_gate
   1193  1.1  thorpej 	    || k->k_metric != ag->ag_metric) {
   1194  1.1  thorpej 		k->k_gate = ag->ag_gate;
   1195  1.1  thorpej 		k->k_metric = ag->ag_metric;
   1196  1.1  thorpej 		k->k_state |= KS_CHANGE;
   1197  1.1  thorpej 	}
   1198  1.1  thorpej 
   1199  1.1  thorpej 	if (k->k_state & KS_DYNAMIC) {
   1200  1.1  thorpej 		k->k_state &= ~KS_DYNAMIC;
   1201  1.1  thorpej 		k->k_state |= (KS_ADD | KS_DEL_ADD);
   1202  1.1  thorpej 	}
   1203  1.1  thorpej 
   1204  1.1  thorpej 	if ((k->k_state & KS_GATEWAY)
   1205  1.1  thorpej 	    && !(ag->ag_state & AGS_GATEWAY)) {
   1206  1.1  thorpej 		k->k_state &= ~KS_GATEWAY;
   1207  1.1  thorpej 		k->k_state |= (KS_ADD | KS_DEL_ADD);
   1208  1.1  thorpej 	} else if (!(k->k_state & KS_GATEWAY)
   1209  1.1  thorpej 		   && (ag->ag_state & AGS_GATEWAY)) {
   1210  1.1  thorpej 		k->k_state |= KS_GATEWAY;
   1211  1.1  thorpej 		k->k_state |= (KS_ADD | KS_DEL_ADD);
   1212  1.1  thorpej 	}
   1213  1.1  thorpej 
   1214  1.1  thorpej 	/* Just delete instead of deleting and then adding a bad route.
   1215  1.1  thorpej 	 * Deleting-and-adding is necessary to change aspects of a route.
   1216  1.1  thorpej 	 * Otherwise, we want to keep the route in the kernel.
   1217  1.1  thorpej 	 */
   1218  1.1  thorpej 	if (k->k_metric == HOPCNT_INFINITY
   1219  1.1  thorpej 	    && (k->k_state & KS_DEL_ADD))
   1220  1.1  thorpej 		k->k_state |= KS_DELETE;
   1221  1.1  thorpej 	else
   1222  1.1  thorpej 		k->k_state &= ~KS_DELETE;
   1223  1.1  thorpej #undef RT
   1224  1.1  thorpej }
   1225  1.1  thorpej 
   1226  1.1  thorpej 
   1227  1.1  thorpej /* ARGSUSED */
   1228  1.1  thorpej static int
   1229  1.2  thorpej walk_kern(struct radix_node *rn, void *argp)
   1230  1.1  thorpej {
   1231  1.1  thorpej #define RT ((struct rt_entry *)rn)
   1232  1.2  thorpej #if 0
   1233  1.2  thorpej 	struct walkarg *w = argp;
   1234  1.2  thorpej #endif
   1235  1.1  thorpej 	char metric, pref;
   1236  1.1  thorpej 	u_int ags = 0;
   1237  1.1  thorpej 
   1238  1.1  thorpej 
   1239  1.1  thorpej 	/* Do not install synthetic routes */
   1240  1.1  thorpej 	if (RT->rt_state & RS_NET_SYN)
   1241  1.1  thorpej 		return 0;
   1242  1.1  thorpej 
   1243  1.1  thorpej 	if (!(RT->rt_state & RS_IF)) {
   1244  1.1  thorpej 		ags |= (AGS_GATEWAY | AGS_SUPPRESS | AGS_PROMOTE);
   1245  1.1  thorpej 
   1246  1.1  thorpej 	} else {
   1247  1.1  thorpej 		/* Do not install routes for "external" remote interfaces.
   1248  1.1  thorpej 		 */
   1249  1.1  thorpej 		if (RT->rt_ifp != 0 && (RT->rt_ifp->int_state & IS_EXTERNAL))
   1250  1.1  thorpej 			return 0;
   1251  1.1  thorpej 
   1252  1.1  thorpej 		ags |= AGS_IF;
   1253  1.1  thorpej 
   1254  1.1  thorpej 		/* If it is not an interface, or an alias for an interface,
   1255  1.1  thorpej 		 * it must be a "gateway."
   1256  1.1  thorpej 		 *
   1257  1.1  thorpej 		 * If it is a "remote" interface, it is also a "gateway" to
   1258  1.1  thorpej 		 * the kernel if is not a alias.
   1259  1.1  thorpej 		 */
   1260  1.1  thorpej 		if (RT->rt_ifp == 0
   1261  1.1  thorpej 		    || ((RT->rt_ifp->int_state & IS_REMOTE)
   1262  1.1  thorpej 			&& RT->rt_ifp->int_metric == 0))
   1263  1.1  thorpej 			ags |= (AGS_GATEWAY | AGS_SUPPRESS | AGS_PROMOTE);
   1264  1.1  thorpej 	}
   1265  1.1  thorpej 
   1266  1.1  thorpej 	if (RT->rt_state & RS_RDISC)
   1267  1.1  thorpej 		ags |= AGS_CORS_GATE;
   1268  1.1  thorpej 
   1269  1.1  thorpej 	/* aggregate good routes without regard to their metric */
   1270  1.1  thorpej 	pref = 1;
   1271  1.1  thorpej 	metric = RT->rt_metric;
   1272  1.1  thorpej 	if (metric == HOPCNT_INFINITY) {
   1273  1.1  thorpej 		/* if the route is dead, so try hard to aggregate. */
   1274  1.1  thorpej 		pref = HOPCNT_INFINITY;
   1275  1.1  thorpej 		ags |= (AGS_FINE_GATE | AGS_SUPPRESS);
   1276  1.1  thorpej 	}
   1277  1.1  thorpej 
   1278  1.1  thorpej 	ag_check(RT->rt_dst, RT->rt_mask, RT->rt_gate, 0,
   1279  1.1  thorpej 		 metric,pref, 0, 0, ags, kern_out);
   1280  1.1  thorpej 	return 0;
   1281  1.1  thorpej #undef RT
   1282  1.1  thorpej }
   1283  1.1  thorpej 
   1284  1.1  thorpej 
   1285  1.1  thorpej /* Update the kernel table to match the daemon table.
   1286  1.1  thorpej  */
   1287  1.1  thorpej static void
   1288  1.1  thorpej fix_kern(void)
   1289  1.1  thorpej {
   1290  1.1  thorpej 	int i, flags;
   1291  1.1  thorpej 	struct khash *k, **pk;
   1292  1.1  thorpej 
   1293  1.1  thorpej 
   1294  1.1  thorpej 	need_kern = age_timer;
   1295  1.1  thorpej 
   1296  1.1  thorpej 	/* Walk daemon table, updating the copy of the kernel table.
   1297  1.1  thorpej 	 */
   1298  1.1  thorpej 	(void)rn_walktree(rhead, walk_kern, 0);
   1299  1.1  thorpej 	ag_flush(0,0,kern_out);
   1300  1.1  thorpej 
   1301  1.1  thorpej 	for (i = 0; i < KHASH_SIZE; i++) {
   1302  1.1  thorpej 		for (pk = &khash_bins[i]; (k = *pk) != 0; ) {
   1303  1.1  thorpej 			/* Do not touch static routes */
   1304  1.1  thorpej 			if (k->k_state & KS_STATIC) {
   1305  1.1  thorpej 				kern_check_static(k,0);
   1306  1.1  thorpej 				pk = &k->k_next;
   1307  1.1  thorpej 				continue;
   1308  1.1  thorpej 			}
   1309  1.1  thorpej 
   1310  1.1  thorpej 			/* check hold on routes deleted by the operator */
   1311  1.1  thorpej 			if (k->k_keep > now.tv_sec) {
   1312  1.1  thorpej 				LIM_SEC(need_kern, k->k_keep);
   1313  1.1  thorpej 				k->k_state |= KS_DELETE;
   1314  1.1  thorpej 				pk = &k->k_next;
   1315  1.1  thorpej 				continue;
   1316  1.1  thorpej 			}
   1317  1.1  thorpej 
   1318  1.1  thorpej 			if (k->k_state & KS_DELETE) {
   1319  1.1  thorpej 				if (!(k->k_state & KS_DELETED))
   1320  1.1  thorpej 					rtioctl(RTM_DELETE,
   1321  1.1  thorpej 						k->k_dst,k->k_gate,
   1322  1.1  thorpej 						k->k_mask, 0, 0);
   1323  1.1  thorpej 				*pk = k->k_next;
   1324  1.1  thorpej 				free(k);
   1325  1.1  thorpej 				continue;
   1326  1.1  thorpej 			}
   1327  1.1  thorpej 
   1328  1.1  thorpej 			if (k->k_state & KS_DEL_ADD)
   1329  1.1  thorpej 				rtioctl(RTM_DELETE,
   1330  1.1  thorpej 					k->k_dst,k->k_gate,k->k_mask, 0, 0);
   1331  1.1  thorpej 
   1332  1.1  thorpej 			flags = (k->k_state & KS_GATEWAY) ? RTF_GATEWAY : 0;
   1333  1.1  thorpej 			if (k->k_state & KS_ADD) {
   1334  1.1  thorpej 				rtioctl(RTM_ADD,
   1335  1.1  thorpej 					k->k_dst, k->k_gate, k->k_mask,
   1336  1.1  thorpej 					k->k_metric, flags);
   1337  1.1  thorpej 			} else if (k->k_state & KS_CHANGE) {
   1338  1.1  thorpej 				rtioctl(RTM_CHANGE,
   1339  1.1  thorpej 					k->k_dst,k->k_gate,k->k_mask,
   1340  1.1  thorpej 					k->k_metric, flags);
   1341  1.1  thorpej 			}
   1342  1.1  thorpej 			k->k_state &= ~(KS_ADD | KS_CHANGE | KS_DEL_ADD);
   1343  1.1  thorpej 
   1344  1.1  thorpej 			/* Mark this route to be deleted in the next cycle.
   1345  1.1  thorpej 			 * This deletes routes that disappear from the
   1346  1.1  thorpej 			 * daemon table, since the normal aging code
   1347  1.1  thorpej 			 * will clear the bit for routes that have not
   1348  1.1  thorpej 			 * disappeared from the daemon table.
   1349  1.1  thorpej 			 */
   1350  1.1  thorpej 			k->k_state |= KS_DELETE;
   1351  1.1  thorpej 			pk = &k->k_next;
   1352  1.1  thorpej 		}
   1353  1.1  thorpej 	}
   1354  1.1  thorpej }
   1355  1.1  thorpej 
   1356  1.1  thorpej 
   1357  1.1  thorpej /* Delete a static route in the image of the kernel table.
   1358  1.1  thorpej  */
   1359  1.1  thorpej void
   1360  1.1  thorpej del_static(naddr dst,
   1361  1.1  thorpej 	   naddr mask,
   1362  1.1  thorpej 	   int gone)
   1363  1.1  thorpej {
   1364  1.1  thorpej 	struct khash *k;
   1365  1.1  thorpej 	struct rt_entry *rt;
   1366  1.1  thorpej 
   1367  1.1  thorpej 	/* Just mark it in the table to be deleted next time the kernel
   1368  1.1  thorpej 	 * table is updated.
   1369  1.1  thorpej 	 * If it has already been deleted, mark it as such, and set its
   1370  1.1  thorpej 	 * keep-timer so that it will not be deleted again for a while.
   1371  1.1  thorpej 	 * This lets the operator delete a route added by the daemon
   1372  1.1  thorpej 	 * and add a replacement.
   1373  1.1  thorpej 	 */
   1374  1.1  thorpej 	k = kern_find(dst, mask, 0);
   1375  1.1  thorpej 	if (k != 0) {
   1376  1.1  thorpej 		k->k_state &= ~KS_STATIC;
   1377  1.1  thorpej 		k->k_state |= KS_DELETE;
   1378  1.1  thorpej 		if (gone) {
   1379  1.1  thorpej 			k->k_state |= KS_DELETED;
   1380  1.1  thorpej 			k->k_keep = now.tv_sec + K_KEEP_LIM;
   1381  1.1  thorpej 		}
   1382  1.1  thorpej 	}
   1383  1.1  thorpej 
   1384  1.1  thorpej 	rt = rtget(dst, mask);
   1385  1.1  thorpej 	if (rt != 0 && (rt->rt_state & RS_STATIC))
   1386  1.1  thorpej 		rtbad(rt);
   1387  1.1  thorpej }
   1388  1.1  thorpej 
   1389  1.1  thorpej 
   1390  1.1  thorpej /* Delete all routes generated from ICMP Redirects that use a given
   1391  1.1  thorpej  * gateway, as well as all old redirected routes.
   1392  1.1  thorpej  */
   1393  1.1  thorpej void
   1394  1.1  thorpej del_redirects(naddr bad_gate,
   1395  1.1  thorpej 	      time_t old)
   1396  1.1  thorpej {
   1397  1.1  thorpej 	int i;
   1398  1.1  thorpej 	struct khash *k;
   1399  1.1  thorpej 
   1400  1.1  thorpej 
   1401  1.1  thorpej 	for (i = 0; i < KHASH_SIZE; i++) {
   1402  1.1  thorpej 		for (k = khash_bins[i]; k != 0; k = k->k_next) {
   1403  1.1  thorpej 			if (!(k->k_state & KS_DYNAMIC)
   1404  1.1  thorpej 			    || (k->k_state & KS_STATIC))
   1405  1.1  thorpej 				continue;
   1406  1.1  thorpej 
   1407  1.1  thorpej 			if (k->k_gate != bad_gate
   1408  1.1  thorpej 			    && k->k_redirect_time > old
   1409  1.1  thorpej 			    && !supplier)
   1410  1.1  thorpej 				continue;
   1411  1.1  thorpej 
   1412  1.1  thorpej 			k->k_state |= KS_DELETE;
   1413  1.1  thorpej 			need_kern.tv_sec = now.tv_sec;
   1414  1.1  thorpej 			trace_act("mark redirected %s --> %s for deletion\n",
   1415  1.1  thorpej 				  addrname(k->k_dst, k->k_mask, 0),
   1416  1.1  thorpej 				  naddr_ntoa(k->k_gate));
   1417  1.1  thorpej 		}
   1418  1.1  thorpej 	}
   1419  1.1  thorpej }
   1420  1.1  thorpej 
   1421  1.1  thorpej 
   1422  1.1  thorpej /* Start the daemon tables.
   1423  1.1  thorpej  */
   1424  1.1  thorpej void
   1425  1.1  thorpej rtinit(void)
   1426  1.1  thorpej {
   1427  1.1  thorpej 	extern int max_keylen;
   1428  1.1  thorpej 	int i;
   1429  1.1  thorpej 	struct ag_info *ag;
   1430  1.1  thorpej 
   1431  1.1  thorpej 	/* Initialize the radix trees */
   1432  1.1  thorpej 	max_keylen = sizeof(struct sockaddr_in);
   1433  1.1  thorpej 	rn_init();
   1434  1.1  thorpej 	rn_inithead((void**)&rhead, 32);
   1435  1.1  thorpej 
   1436  1.1  thorpej 	/* mark all of the slots in the table free */
   1437  1.1  thorpej 	ag_avail = ag_slots;
   1438  1.1  thorpej 	for (ag = ag_slots, i = 1; i < NUM_AG_SLOTS; i++) {
   1439  1.1  thorpej 		ag->ag_fine = ag+1;
   1440  1.1  thorpej 		ag++;
   1441  1.1  thorpej 	}
   1442  1.1  thorpej }
   1443  1.1  thorpej 
   1444  1.1  thorpej 
   1445  1.1  thorpej #ifdef _HAVE_SIN_LEN
   1446  1.1  thorpej static struct sockaddr_in dst_sock = {sizeof(dst_sock), AF_INET};
   1447  1.1  thorpej static struct sockaddr_in mask_sock = {sizeof(mask_sock), AF_INET};
   1448  1.1  thorpej #else
   1449  1.1  thorpej static struct sockaddr_in_new dst_sock = {_SIN_ADDR_SIZE, AF_INET};
   1450  1.1  thorpej static struct sockaddr_in_new mask_sock = {_SIN_ADDR_SIZE, AF_INET};
   1451  1.1  thorpej #endif
   1452  1.1  thorpej 
   1453  1.1  thorpej 
   1454  1.1  thorpej void
   1455  1.1  thorpej set_need_flash(void)
   1456  1.1  thorpej {
   1457  1.1  thorpej 	if (!need_flash) {
   1458  1.1  thorpej 		need_flash = 1;
   1459  1.1  thorpej 		/* Do not send the flash update immediately.  Wait a little
   1460  1.1  thorpej 		 * while to hear from other routers.
   1461  1.1  thorpej 		 */
   1462  1.1  thorpej 		no_flash.tv_sec = now.tv_sec + MIN_WAITTIME;
   1463  1.1  thorpej 	}
   1464  1.1  thorpej }
   1465  1.1  thorpej 
   1466  1.1  thorpej 
   1467  1.1  thorpej /* Get a particular routing table entry
   1468  1.1  thorpej  */
   1469  1.1  thorpej struct rt_entry *
   1470  1.1  thorpej rtget(naddr dst, naddr mask)
   1471  1.1  thorpej {
   1472  1.1  thorpej 	struct rt_entry *rt;
   1473  1.1  thorpej 
   1474  1.1  thorpej 	dst_sock.sin_addr.s_addr = dst;
   1475  1.1  thorpej 	mask_sock.sin_addr.s_addr = mask;
   1476  1.1  thorpej 	masktrim(&mask_sock);
   1477  1.1  thorpej 	rt = (struct rt_entry *)rhead->rnh_lookup(&dst_sock,&mask_sock,rhead);
   1478  1.1  thorpej 	if (!rt
   1479  1.1  thorpej 	    || rt->rt_dst != dst
   1480  1.1  thorpej 	    || rt->rt_mask != mask)
   1481  1.1  thorpej 		return 0;
   1482  1.1  thorpej 
   1483  1.1  thorpej 	return rt;
   1484  1.1  thorpej }
   1485  1.1  thorpej 
   1486  1.1  thorpej 
   1487  1.1  thorpej /* Find a route to dst as the kernel would.
   1488  1.1  thorpej  */
   1489  1.1  thorpej struct rt_entry *
   1490  1.1  thorpej rtfind(naddr dst)
   1491  1.1  thorpej {
   1492  1.1  thorpej 	dst_sock.sin_addr.s_addr = dst;
   1493  1.1  thorpej 	return (struct rt_entry *)rhead->rnh_matchaddr(&dst_sock, rhead);
   1494  1.1  thorpej }
   1495  1.1  thorpej 
   1496  1.1  thorpej 
   1497  1.1  thorpej /* add a route to the table
   1498  1.1  thorpej  */
   1499  1.1  thorpej void
   1500  1.1  thorpej rtadd(naddr	dst,
   1501  1.1  thorpej       naddr	mask,
   1502  1.1  thorpej       naddr	gate,			/* forward packets here */
   1503  1.1  thorpej       naddr	router,			/* on the authority of this router */
   1504  1.1  thorpej       int	metric,
   1505  1.1  thorpej       u_short	tag,
   1506  1.1  thorpej       u_int	state,			/* rs_state for the entry */
   1507  1.1  thorpej       struct interface *ifp)
   1508  1.1  thorpej {
   1509  1.1  thorpej 	struct rt_entry *rt;
   1510  1.1  thorpej 	naddr smask;
   1511  1.1  thorpej 	int i;
   1512  1.1  thorpej 	struct rt_spare *rts;
   1513  1.1  thorpej 
   1514  1.1  thorpej 	rt = (struct rt_entry *)malloc(sizeof (*rt));
   1515  1.1  thorpej 	if (rt == 0) {
   1516  1.1  thorpej 		BADERR(1,"rtadd malloc");
   1517  1.1  thorpej 		return;
   1518  1.1  thorpej 	}
   1519  1.1  thorpej 	bzero(rt, sizeof(*rt));
   1520  1.1  thorpej 	for (rts = rt->rt_spares, i = NUM_SPARES; i != 0; i--, rts++)
   1521  1.1  thorpej 		rts->rts_metric = HOPCNT_INFINITY;
   1522  1.1  thorpej 
   1523  1.1  thorpej 	rt->rt_nodes->rn_key = (caddr_t)&rt->rt_dst_sock;
   1524  1.1  thorpej 	rt->rt_dst = dst;
   1525  1.1  thorpej 	rt->rt_dst_sock.sin_family = AF_INET;
   1526  1.1  thorpej #ifdef _HAVE_SIN_LEN
   1527  1.1  thorpej 	rt->rt_dst_sock.sin_len = dst_sock.sin_len;
   1528  1.1  thorpej #endif
   1529  1.1  thorpej 	if (mask != HOST_MASK) {
   1530  1.1  thorpej 		smask = std_mask(dst);
   1531  1.1  thorpej 		if ((smask & ~mask) == 0 && mask > smask)
   1532  1.1  thorpej 			state |= RS_SUBNET;
   1533  1.1  thorpej 	}
   1534  1.1  thorpej 	mask_sock.sin_addr.s_addr = mask;
   1535  1.1  thorpej 	masktrim(&mask_sock);
   1536  1.1  thorpej 	rt->rt_mask = mask;
   1537  1.1  thorpej 	rt->rt_state = state;
   1538  1.1  thorpej 	rt->rt_gate = gate;
   1539  1.1  thorpej 	rt->rt_router = router;
   1540  1.1  thorpej 	rt->rt_time = now.tv_sec;
   1541  1.1  thorpej 	rt->rt_metric = metric;
   1542  1.1  thorpej 	rt->rt_poison_metric = HOPCNT_INFINITY;
   1543  1.1  thorpej 	rt->rt_tag = tag;
   1544  1.1  thorpej 	rt->rt_ifp = ifp;
   1545  1.1  thorpej 	rt->rt_seqno = update_seqno;
   1546  1.1  thorpej 
   1547  1.1  thorpej 	if (TRACEACTIONS)
   1548  1.1  thorpej 		trace_add_del("Add", rt);
   1549  1.1  thorpej 
   1550  1.1  thorpej 	need_kern.tv_sec = now.tv_sec;
   1551  1.1  thorpej 	set_need_flash();
   1552  1.1  thorpej 
   1553  1.1  thorpej 	if (0 == rhead->rnh_addaddr(&rt->rt_dst_sock, &mask_sock,
   1554  1.1  thorpej 				    rhead, rt->rt_nodes)) {
   1555  1.1  thorpej 		msglog("rnh_addaddr() failed for %s mask=%#x",
   1556  1.1  thorpej 		       naddr_ntoa(dst), mask);
   1557  1.1  thorpej 	}
   1558  1.1  thorpej }
   1559  1.1  thorpej 
   1560  1.1  thorpej 
   1561  1.1  thorpej /* notice a changed route
   1562  1.1  thorpej  */
   1563  1.1  thorpej void
   1564  1.1  thorpej rtchange(struct rt_entry *rt,
   1565  1.1  thorpej 	 u_int	state,			/* new state bits */
   1566  1.1  thorpej 	 naddr	gate,			/* now forward packets here */
   1567  1.1  thorpej 	 naddr	router,			/* on the authority of this router */
   1568  1.1  thorpej 	 int	metric,			/* new metric */
   1569  1.1  thorpej 	 u_short tag,
   1570  1.1  thorpej 	 struct interface *ifp,
   1571  1.1  thorpej 	 time_t	new_time,
   1572  1.1  thorpej 	 char	*label)
   1573  1.1  thorpej {
   1574  1.1  thorpej 	if (rt->rt_metric != metric) {
   1575  1.1  thorpej 		/* Fix the kernel immediately if it seems the route
   1576  1.1  thorpej 		 * has gone bad, since there may be a working route that
   1577  1.1  thorpej 		 * aggregates this route.
   1578  1.1  thorpej 		 */
   1579  1.1  thorpej 		if (metric == HOPCNT_INFINITY)
   1580  1.1  thorpej 			need_kern.tv_sec = now.tv_sec;
   1581  1.1  thorpej 		rt->rt_seqno = update_seqno;
   1582  1.1  thorpej 		set_need_flash();
   1583  1.1  thorpej 	}
   1584  1.1  thorpej 
   1585  1.1  thorpej 	if (rt->rt_gate != gate) {
   1586  1.1  thorpej 		need_kern.tv_sec = now.tv_sec;
   1587  1.1  thorpej 		rt->rt_seqno = update_seqno;
   1588  1.1  thorpej 		set_need_flash();
   1589  1.1  thorpej 	}
   1590  1.1  thorpej 
   1591  1.1  thorpej 	state |= (rt->rt_state & RS_SUBNET);
   1592  1.1  thorpej 
   1593  1.1  thorpej 	if (TRACEACTIONS)
   1594  1.1  thorpej 		trace_change(rt, state, gate, router, metric, tag, ifp,
   1595  1.1  thorpej 			     new_time,
   1596  1.1  thorpej 			     label ? label : "Chg   ");
   1597  1.1  thorpej 
   1598  1.1  thorpej 	rt->rt_state = state;
   1599  1.1  thorpej 	rt->rt_gate = gate;
   1600  1.1  thorpej 	rt->rt_router = router;
   1601  1.1  thorpej 	rt->rt_metric = metric;
   1602  1.1  thorpej 	rt->rt_tag = tag;
   1603  1.1  thorpej 	rt->rt_ifp = ifp;
   1604  1.1  thorpej 	rt->rt_time = new_time;
   1605  1.1  thorpej }
   1606  1.1  thorpej 
   1607  1.1  thorpej 
   1608  1.1  thorpej /* check for a better route among the spares
   1609  1.1  thorpej  */
   1610  1.1  thorpej static struct rt_spare *
   1611  1.1  thorpej rts_better(struct rt_entry *rt)
   1612  1.1  thorpej {
   1613  1.1  thorpej 	struct rt_spare *rts, *rts1;
   1614  1.1  thorpej 	int i;
   1615  1.1  thorpej 
   1616  1.1  thorpej 	/* find the best alternative among the spares */
   1617  1.1  thorpej 	rts = rt->rt_spares+1;
   1618  1.1  thorpej 	for (i = NUM_SPARES, rts1 = rts+1; i > 2; i--, rts1++) {
   1619  1.1  thorpej 		if (BETTER_LINK(rt,rts1,rts))
   1620  1.1  thorpej 			rts = rts1;
   1621  1.1  thorpej 	}
   1622  1.1  thorpej 
   1623  1.1  thorpej 	return rts;
   1624  1.1  thorpej }
   1625  1.1  thorpej 
   1626  1.1  thorpej 
   1627  1.1  thorpej /* switch to a backup route
   1628  1.1  thorpej  */
   1629  1.1  thorpej void
   1630  1.1  thorpej rtswitch(struct rt_entry *rt,
   1631  1.1  thorpej 	 struct rt_spare *rts)
   1632  1.1  thorpej {
   1633  1.1  thorpej 	struct rt_spare swap;
   1634  1.1  thorpej 	char label[10];
   1635  1.1  thorpej 
   1636  1.1  thorpej 
   1637  1.1  thorpej 	/* Do not change permanent routes */
   1638  1.1  thorpej 	if (0 != (rt->rt_state & RS_PERMANENT))
   1639  1.1  thorpej 		return;
   1640  1.1  thorpej 
   1641  1.1  thorpej 	/* Do not discard synthetic routes until they go bad */
   1642  1.1  thorpej 	if ((rt->rt_state & RS_NET_SYN)
   1643  1.1  thorpej 	    && rt->rt_metric < HOPCNT_INFINITY)
   1644  1.1  thorpej 		return;
   1645  1.1  thorpej 
   1646  1.1  thorpej 	/* find the best alternative among the spares */
   1647  1.1  thorpej 	if (rts == 0)
   1648  1.1  thorpej 		rts = rts_better(rt);
   1649  1.1  thorpej 
   1650  1.1  thorpej 	/* Do not bother if it is not worthwhile.
   1651  1.1  thorpej 	 */
   1652  1.1  thorpej 	if (!BETTER_LINK(rt, rts, rt->rt_spares))
   1653  1.1  thorpej 		return;
   1654  1.1  thorpej 
   1655  1.1  thorpej 	swap = rt->rt_spares[0];
   1656  1.1  thorpej 	(void)sprintf(label, "Use #%d", rts - rt->rt_spares);
   1657  1.1  thorpej 	rtchange(rt, rt->rt_state & ~(RS_NET_SYN | RS_RDISC),
   1658  1.1  thorpej 		 rts->rts_gate, rts->rts_router, rts->rts_metric,
   1659  1.1  thorpej 		 rts->rts_tag, rts->rts_ifp, rts->rts_time, label);
   1660  1.1  thorpej 	*rts = swap;
   1661  1.1  thorpej }
   1662  1.1  thorpej 
   1663  1.1  thorpej 
   1664  1.1  thorpej void
   1665  1.1  thorpej rtdelete(struct rt_entry *rt)
   1666  1.1  thorpej {
   1667  1.1  thorpej 	struct khash *k;
   1668  1.1  thorpej 
   1669  1.1  thorpej 
   1670  1.1  thorpej 	if (TRACEACTIONS)
   1671  1.1  thorpej 		trace_add_del("Del", rt);
   1672  1.1  thorpej 
   1673  1.1  thorpej 	k = kern_find(rt->rt_dst, rt->rt_mask, 0);
   1674  1.1  thorpej 	if (k != 0) {
   1675  1.1  thorpej 		k->k_state |= KS_DELETE;
   1676  1.1  thorpej 		need_kern.tv_sec = now.tv_sec;
   1677  1.1  thorpej 	}
   1678  1.1  thorpej 
   1679  1.1  thorpej 	dst_sock.sin_addr.s_addr = rt->rt_dst;
   1680  1.1  thorpej 	mask_sock.sin_addr.s_addr = rt->rt_mask;
   1681  1.1  thorpej 	masktrim(&mask_sock);
   1682  1.1  thorpej 	if (rt != (struct rt_entry *)rhead->rnh_deladdr(&dst_sock, &mask_sock,
   1683  1.1  thorpej 							rhead)) {
   1684  1.1  thorpej 		msglog("rnh_deladdr() failed");
   1685  1.1  thorpej 	} else {
   1686  1.1  thorpej 		free(rt);
   1687  1.1  thorpej 	}
   1688  1.1  thorpej }
   1689  1.1  thorpej 
   1690  1.1  thorpej 
   1691  1.1  thorpej /* Get rid of a bad route, and try to switch to a replacement.
   1692  1.1  thorpej  */
   1693  1.1  thorpej void
   1694  1.1  thorpej rtbad(struct rt_entry *rt)
   1695  1.1  thorpej {
   1696  1.1  thorpej 	/* Poison the route */
   1697  1.1  thorpej 	rtchange(rt, rt->rt_state & ~(RS_IF | RS_LOCAL | RS_STATIC),
   1698  1.1  thorpej 		 rt->rt_gate, rt->rt_router, HOPCNT_INFINITY, rt->rt_tag,
   1699  1.1  thorpej 		 0, rt->rt_time, 0);
   1700  1.1  thorpej 
   1701  1.1  thorpej 	rtswitch(rt, 0);
   1702  1.1  thorpej }
   1703  1.1  thorpej 
   1704  1.1  thorpej 
   1705  1.1  thorpej /* Junk a RS_NET_SYN or RS_LOCAL route,
   1706  1.1  thorpej  *	unless it is needed by another interface.
   1707  1.1  thorpej  */
   1708  1.1  thorpej void
   1709  1.1  thorpej rtbad_sub(struct rt_entry *rt)
   1710  1.1  thorpej {
   1711  1.1  thorpej 	struct interface *ifp, *ifp1;
   1712  1.1  thorpej 	struct intnet *intnetp;
   1713  1.1  thorpej 	u_int state;
   1714  1.1  thorpej 
   1715  1.1  thorpej 
   1716  1.1  thorpej 	ifp1 = 0;
   1717  1.1  thorpej 	state = 0;
   1718  1.1  thorpej 
   1719  1.1  thorpej 	if (rt->rt_state & RS_LOCAL) {
   1720  1.1  thorpej 		/* Is this the route through loopback for the interface?
   1721  1.1  thorpej 		 * If so, see if it is used by any other interfaces, such
   1722  1.1  thorpej 		 * as a point-to-point interface with the same local address.
   1723  1.1  thorpej 		 */
   1724  1.1  thorpej 		for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) {
   1725  1.1  thorpej 			/* Retain it if another interface needs it.
   1726  1.1  thorpej 			 */
   1727  1.1  thorpej 			if (ifp->int_addr == rt->rt_ifp->int_addr) {
   1728  1.1  thorpej 				state |= RS_LOCAL;
   1729  1.1  thorpej 				ifp1 = ifp;
   1730  1.1  thorpej 				break;
   1731  1.1  thorpej 			}
   1732  1.1  thorpej 		}
   1733  1.1  thorpej 
   1734  1.1  thorpej 	}
   1735  1.1  thorpej 
   1736  1.1  thorpej 	if (!(state & RS_LOCAL)) {
   1737  1.1  thorpej 		/* Retain RIPv1 logical network route if there is another
   1738  1.1  thorpej 		 * interface that justifies it.
   1739  1.1  thorpej 		 */
   1740  1.1  thorpej 		if (rt->rt_state & RS_NET_SYN) {
   1741  1.1  thorpej 			for (ifp = ifnet; ifp != 0; ifp = ifp->int_next) {
   1742  1.1  thorpej 				if ((ifp->int_state & IS_NEED_NET_SYN)
   1743  1.1  thorpej 				    && rt->rt_mask == ifp->int_std_mask
   1744  1.1  thorpej 				    && rt->rt_dst == ifp->int_std_addr) {
   1745  1.1  thorpej 					state |= RS_NET_SYN;
   1746  1.1  thorpej 					ifp1 = ifp;
   1747  1.1  thorpej 					break;
   1748  1.1  thorpej 				}
   1749  1.1  thorpej 			}
   1750  1.1  thorpej 		}
   1751  1.1  thorpej 
   1752  1.1  thorpej 		/* or if there is an authority route that needs it. */
   1753  1.1  thorpej 		for (intnetp = intnets;
   1754  1.1  thorpej 		     intnetp != 0;
   1755  1.1  thorpej 		     intnetp = intnetp->intnet_next) {
   1756  1.1  thorpej 			if (intnetp->intnet_addr == rt->rt_dst
   1757  1.1  thorpej 			    && intnetp->intnet_mask == rt->rt_mask) {
   1758  1.1  thorpej 				state |= (RS_NET_SYN | RS_NET_INT);
   1759  1.1  thorpej 				break;
   1760  1.1  thorpej 			}
   1761  1.1  thorpej 		}
   1762  1.1  thorpej 	}
   1763  1.1  thorpej 
   1764  1.1  thorpej 	if (ifp1 != 0 || (state & RS_NET_SYN)) {
   1765  1.1  thorpej 		rtchange(rt, ((rt->rt_state & ~(RS_NET_SYN | RS_LOCAL))
   1766  1.1  thorpej 			      | state),
   1767  1.1  thorpej 			 rt->rt_gate, rt->rt_router, rt->rt_metric,
   1768  1.1  thorpej 			 rt->rt_tag, ifp1, rt->rt_time, 0);
   1769  1.1  thorpej 	} else {
   1770  1.1  thorpej 		rtbad(rt);
   1771  1.1  thorpej 	}
   1772  1.1  thorpej }
   1773  1.1  thorpej 
   1774  1.1  thorpej 
   1775  1.1  thorpej /* Called while walking the table looking for sick interfaces
   1776  1.1  thorpej  * or after a time change.
   1777  1.1  thorpej  */
   1778  1.1  thorpej /* ARGSUSED */
   1779  1.1  thorpej int
   1780  1.2  thorpej walk_bad(struct radix_node *rn, void *argp)
   1781  1.1  thorpej {
   1782  1.1  thorpej #define RT ((struct rt_entry *)rn)
   1783  1.2  thorpej #if 0
   1784  1.2  thorpej 	struct walkarg *w = argp;	/* not used */
   1785  1.2  thorpej #endif
   1786  1.1  thorpej 	struct rt_spare *rts;
   1787  1.1  thorpej 	int i;
   1788  1.1  thorpej 	time_t new_time;
   1789  1.1  thorpej 
   1790  1.1  thorpej 
   1791  1.1  thorpej 	/* fix any spare routes through the interface
   1792  1.1  thorpej 	 */
   1793  1.1  thorpej 	rts = RT->rt_spares;
   1794  1.1  thorpej 	for (i = NUM_SPARES; i != 1; i--) {
   1795  1.1  thorpej 		rts++;
   1796  1.1  thorpej 
   1797  1.1  thorpej 		if (rts->rts_ifp != 0
   1798  1.1  thorpej 		    && (rts->rts_ifp->int_state & IS_BROKE)) {
   1799  1.1  thorpej 			new_time = rts->rts_time;
   1800  1.1  thorpej 			if (new_time >= now_garbage)
   1801  1.1  thorpej 				new_time = now_garbage-1;
   1802  1.1  thorpej 			trace_upslot(RT, rts, rts->rts_gate,
   1803  1.1  thorpej 				     rts->rts_router, 0,
   1804  1.1  thorpej 				     HOPCNT_INFINITY, rts->rts_tag,
   1805  1.1  thorpej 				     new_time);
   1806  1.1  thorpej 			rts->rts_ifp = 0;
   1807  1.1  thorpej 			rts->rts_metric = HOPCNT_INFINITY;
   1808  1.1  thorpej 			rts->rts_time = new_time;
   1809  1.1  thorpej 		}
   1810  1.1  thorpej 	}
   1811  1.1  thorpej 
   1812  1.1  thorpej 	/* Deal with the main route
   1813  1.1  thorpej 	 */
   1814  1.1  thorpej 	/* finished if it has been handled before or if its interface is ok
   1815  1.1  thorpej 	 */
   1816  1.1  thorpej 	if (RT->rt_ifp == 0 || !(RT->rt_ifp->int_state & IS_BROKE))
   1817  1.1  thorpej 		return 0;
   1818  1.1  thorpej 
   1819  1.1  thorpej 	/* Bad routes for other than interfaces are easy.
   1820  1.1  thorpej 	 */
   1821  1.1  thorpej 	if (0 == (RT->rt_state & (RS_IF | RS_NET_SYN | RS_LOCAL))) {
   1822  1.1  thorpej 		rtbad(RT);
   1823  1.1  thorpej 		return 0;
   1824  1.1  thorpej 	}
   1825  1.1  thorpej 
   1826  1.1  thorpej 	rtbad_sub(RT);
   1827  1.1  thorpej 	return 0;
   1828  1.1  thorpej #undef RT
   1829  1.1  thorpej }
   1830  1.1  thorpej 
   1831  1.1  thorpej 
   1832  1.1  thorpej /* Check the age of an individual route.
   1833  1.1  thorpej  */
   1834  1.1  thorpej /* ARGSUSED */
   1835  1.1  thorpej static int
   1836  1.2  thorpej walk_age(struct radix_node *rn, void *argp)
   1837  1.1  thorpej {
   1838  1.1  thorpej #define RT ((struct rt_entry *)rn)
   1839  1.2  thorpej #if 0
   1840  1.2  thorpej 	struct walkarg *w = argp;	/* not used */
   1841  1.2  thorpej #endif
   1842  1.1  thorpej 	struct interface *ifp;
   1843  1.1  thorpej 	struct rt_spare *rts;
   1844  1.1  thorpej 	int i;
   1845  1.1  thorpej 
   1846  1.1  thorpej 
   1847  1.1  thorpej 	/* age all of the spare routes, including the primary route
   1848  1.1  thorpej 	 * currently in use
   1849  1.1  thorpej 	 */
   1850  1.1  thorpej 	rts = RT->rt_spares;
   1851  1.1  thorpej 	for (i = NUM_SPARES; i != 0; i--, rts++) {
   1852  1.1  thorpej 
   1853  1.1  thorpej 		ifp = rts->rts_ifp;
   1854  1.1  thorpej 		if (i == NUM_SPARES) {
   1855  1.1  thorpej 			if (!AGE_RT(RT, ifp)) {
   1856  1.1  thorpej 				/* Keep various things from deciding ageless
   1857  1.1  thorpej 				 * routes are stale */
   1858  1.1  thorpej 				rts->rts_time = now.tv_sec;
   1859  1.1  thorpej 				continue;
   1860  1.1  thorpej 			}
   1861  1.1  thorpej 
   1862  1.1  thorpej 			/* forget RIP routes after RIP has been turned off.
   1863  1.1  thorpej 			 */
   1864  1.1  thorpej 			if (rip_sock < 0) {
   1865  1.1  thorpej 				rtdelete(RT);
   1866  1.1  thorpej 				return 0;
   1867  1.1  thorpej 			}
   1868  1.1  thorpej 		}
   1869  1.1  thorpej 
   1870  1.1  thorpej 		/* age failing routes
   1871  1.1  thorpej 		 */
   1872  1.1  thorpej 		if (age_bad_gate == rts->rts_gate
   1873  1.1  thorpej 		    && rts->rts_time >= now_stale) {
   1874  1.1  thorpej 			rts->rts_time -= SUPPLY_INTERVAL;
   1875  1.1  thorpej 		}
   1876  1.1  thorpej 
   1877  1.1  thorpej 		/* trash the spare routes when they go bad */
   1878  1.1  thorpej 		if (rts->rts_metric < HOPCNT_INFINITY
   1879  1.1  thorpej 		    && now_garbage > rts->rts_time) {
   1880  1.1  thorpej 			trace_upslot(RT, rts, rts->rts_gate,
   1881  1.1  thorpej 				     rts->rts_router, rts->rts_ifp,
   1882  1.1  thorpej 				     HOPCNT_INFINITY, rts->rts_tag,
   1883  1.1  thorpej 				     rts->rts_time);
   1884  1.1  thorpej 			rts->rts_metric = HOPCNT_INFINITY;
   1885  1.1  thorpej 		}
   1886  1.1  thorpej 	}
   1887  1.1  thorpej 
   1888  1.1  thorpej 
   1889  1.1  thorpej 	/* finished if the active route is still fresh */
   1890  1.1  thorpej 	if (now_stale <= RT->rt_time)
   1891  1.1  thorpej 		return 0;
   1892  1.1  thorpej 
   1893  1.1  thorpej 	/* try to switch to an alternative */
   1894  1.1  thorpej 	rtswitch(RT, 0);
   1895  1.1  thorpej 
   1896  1.1  thorpej 	/* Delete a dead route after it has been publically mourned. */
   1897  1.1  thorpej 	if (now_garbage > RT->rt_time) {
   1898  1.1  thorpej 		rtdelete(RT);
   1899  1.1  thorpej 		return 0;
   1900  1.1  thorpej 	}
   1901  1.1  thorpej 
   1902  1.1  thorpej 	/* Start poisoning a bad route before deleting it. */
   1903  1.1  thorpej 	if (now.tv_sec - RT->rt_time > EXPIRE_TIME)
   1904  1.1  thorpej 		rtchange(RT, RT->rt_state, RT->rt_gate, RT->rt_router,
   1905  1.1  thorpej 			 HOPCNT_INFINITY, RT->rt_tag, RT->rt_ifp,
   1906  1.1  thorpej 			 RT->rt_time, 0);
   1907  1.1  thorpej 	return 0;
   1908  1.1  thorpej }
   1909  1.1  thorpej 
   1910  1.1  thorpej 
   1911  1.1  thorpej /* Watch for dead routes and interfaces.
   1912  1.1  thorpej  */
   1913  1.1  thorpej void
   1914  1.1  thorpej age(naddr bad_gate)
   1915  1.1  thorpej {
   1916  1.1  thorpej 	struct interface *ifp;
   1917  1.1  thorpej 
   1918  1.1  thorpej 
   1919  1.1  thorpej 	age_timer.tv_sec = now.tv_sec + (rip_sock < 0
   1920  1.1  thorpej 					 ? NEVER
   1921  1.1  thorpej 					 : SUPPLY_INTERVAL);
   1922  1.1  thorpej 
   1923  1.1  thorpej 	for (ifp = ifnet; ifp; ifp = ifp->int_next) {
   1924  1.1  thorpej 		/* Check for dead IS_REMOTE interfaces by timing their
   1925  1.1  thorpej 		 * transmissions.
   1926  1.1  thorpej 		 */
   1927  1.1  thorpej 		if ((ifp->int_state & IS_REMOTE)
   1928  1.1  thorpej 		    && !(ifp->int_state & IS_PASSIVE)
   1929  1.1  thorpej 		    && (ifp->int_state & IS_ACTIVE)) {
   1930  1.1  thorpej 			LIM_SEC(age_timer, now.tv_sec+SUPPLY_INTERVAL);
   1931  1.1  thorpej 
   1932  1.1  thorpej 			if (now.tv_sec - ifp->int_act_time > EXPIRE_TIME
   1933  1.1  thorpej 			    && !(ifp->int_state & IS_BROKE)) {
   1934  1.1  thorpej 				msglog("remote interface %s to %s timed out"
   1935  1.1  thorpej 				       "--turned off",
   1936  1.1  thorpej 				       ifp->int_name,
   1937  1.1  thorpej 				       naddr_ntoa(ifp->int_addr));
   1938  1.1  thorpej 				if_bad(ifp);
   1939  1.1  thorpej 			}
   1940  1.1  thorpej 		}
   1941  1.1  thorpej 	}
   1942  1.1  thorpej 
   1943  1.1  thorpej 	/* Age routes. */
   1944  1.1  thorpej 	age_bad_gate = bad_gate;
   1945  1.1  thorpej 	(void)rn_walktree(rhead, walk_age, 0);
   1946  1.1  thorpej 
   1947  1.1  thorpej 	/* Update the kernel routing table. */
   1948  1.1  thorpej 	fix_kern();
   1949  1.1  thorpej }
   1950