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