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