Home | History | Annotate | Line # | Download | only in mrouted
      1  1.13     lukem /*	$NetBSD: route.c,v 1.13 2009/04/17 16:05:43 lukem Exp $	*/
      2   1.4   thorpej 
      3   1.1    brezak /*
      4   1.1    brezak  * The mrouted program is covered by the license in the accompanying file
      5   1.1    brezak  * named "LICENSE".  Use of the mrouted program represents acceptance of
      6   1.1    brezak  * the terms and conditions listed in that file.
      7   1.1    brezak  *
      8   1.1    brezak  * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
      9   1.1    brezak  * Leland Stanford Junior University.
     10   1.1    brezak  */
     11   1.1    brezak 
     12   1.1    brezak 
     13   1.1    brezak #include "defs.h"
     14   1.1    brezak 
     15   1.1    brezak 
     16   1.1    brezak /*
     17   1.3   mycroft  * This define statement saves a lot of space later
     18   1.3   mycroft  */
     19   1.3   mycroft #define RT_ADDR	(struct rtentry *)&routing_table
     20   1.3   mycroft 
     21   1.3   mycroft /*
     22   1.1    brezak  * Exported variables.
     23   1.1    brezak  */
     24   1.1    brezak int routes_changed;			/* 1=>some routes have changed */
     25   1.1    brezak int delay_change_reports;		/* 1=>postpone change reports  */
     26   1.1    brezak 
     27   1.1    brezak 
     28   1.1    brezak /*
     29   1.3   mycroft  * The routing table is shared with prune.c , so must not be static.
     30   1.3   mycroft  */
     31   1.3   mycroft struct rtentry *routing_table;		/* pointer to list of route entries */
     32   1.3   mycroft 
     33   1.3   mycroft /*
     34   1.1    brezak  * Private variables.
     35   1.1    brezak  */
     36   1.1    brezak static struct rtentry *rtp;		/* pointer to a route entry         */
     37   1.3   mycroft static struct rtentry *rt_end;		/* pointer to last route entry      */
     38   1.3   mycroft unsigned int nroutes;			/* current number of route entries  */
     39   1.1    brezak 
     40   1.1    brezak /*
     41   1.5   mycroft  * Private functions.
     42   1.5   mycroft  */
     43   1.7       wiz static int init_children_and_leaves(struct rtentry *r, vifi_t parent);
     44   1.7       wiz static int find_route(u_int32_t origin, u_int32_t mask);
     45   1.7       wiz static void create_route(u_int32_t origin, u_int32_t mask);
     46   1.7       wiz static void discard_route(struct rtentry *prev_r);
     47   1.7       wiz static int compare_rts(const void *rt1, const void *rt2);
     48   1.7       wiz static int report_chunk(struct rtentry *start_rt, vifi_t vifi, u_int32_t dst);
     49   1.5   mycroft 
     50   1.5   mycroft /*
     51   1.1    brezak  * Initialize the routing table and associated variables.
     52   1.1    brezak  */
     53   1.3   mycroft void
     54   1.7       wiz init_routes(void)
     55   1.1    brezak {
     56   1.1    brezak     routing_table        = NULL;
     57   1.5   mycroft     rt_end		 = RT_ADDR;
     58   1.1    brezak     nroutes		 = 0;
     59   1.1    brezak     routes_changed       = FALSE;
     60   1.1    brezak     delay_change_reports = FALSE;
     61   1.1    brezak }
     62   1.1    brezak 
     63   1.1    brezak 
     64   1.1    brezak /*
     65   1.1    brezak  * Initialize the children and leaf bits for route 'r', along with the
     66   1.1    brezak  * associated dominant, subordinate, and leaf timing data structures.
     67   1.1    brezak  * Return TRUE if this changes the value of either the children or
     68   1.1    brezak  * leaf bitmaps for 'r'.
     69   1.1    brezak  */
     70   1.3   mycroft static int
     71   1.7       wiz init_children_and_leaves(struct rtentry *r, vifi_t parent)
     72   1.1    brezak {
     73   1.7       wiz     vifi_t vifi;
     74   1.7       wiz     struct uvif *v;
     75   1.1    brezak     vifbitmap_t old_children, old_leaves;
     76   1.1    brezak 
     77   1.1    brezak     VIFM_COPY(r->rt_children, old_children);
     78   1.1    brezak     VIFM_COPY(r->rt_leaves,   old_leaves  );
     79   1.1    brezak 
     80   1.1    brezak     VIFM_CLRALL(r->rt_children);
     81   1.1    brezak     VIFM_CLRALL(r->rt_leaves);
     82   1.1    brezak     r->rt_flags &= ~RTF_LEAF_TIMING;
     83   1.1    brezak 
     84   1.1    brezak     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
     85   1.1    brezak 	r->rt_dominants   [vifi] = 0;
     86   1.1    brezak 	r->rt_subordinates[vifi] = 0;
     87   1.1    brezak 
     88   1.1    brezak 	if (vifi != parent && !(v->uv_flags & (VIFF_DOWN|VIFF_DISABLED))) {
     89   1.1    brezak 	    VIFM_SET(vifi, r->rt_children);
     90   1.1    brezak 	    if (v->uv_neighbors == NULL) {
     91   1.1    brezak 		VIFM_SET(vifi, r->rt_leaves);
     92   1.1    brezak 		r->rt_leaf_timers[vifi] = 0;
     93   1.1    brezak 	    }
     94   1.1    brezak 	    else {
     95   1.1    brezak 		r->rt_leaf_timers[vifi] = LEAF_CONFIRMATION_TIME;
     96   1.1    brezak 		r->rt_flags |= RTF_LEAF_TIMING;
     97   1.1    brezak 	    }
     98   1.1    brezak 	}
     99   1.1    brezak 	else {
    100   1.1    brezak 	    r->rt_leaf_timers[vifi] = 0;
    101   1.1    brezak 	}
    102   1.1    brezak     }
    103   1.1    brezak 
    104   1.1    brezak     return (!VIFM_SAME(r->rt_children, old_children) ||
    105   1.1    brezak 	    !VIFM_SAME(r->rt_leaves,   old_leaves));
    106   1.1    brezak }
    107   1.1    brezak 
    108   1.1    brezak 
    109   1.1    brezak /*
    110   1.1    brezak  * A new vif has come up -- update the children and leaf bitmaps in all route
    111   1.1    brezak  * entries to take that into account.
    112   1.1    brezak  */
    113   1.3   mycroft void
    114   1.7       wiz add_vif_to_routes(vifi_t vifi)
    115   1.1    brezak {
    116   1.7       wiz     struct rtentry *r;
    117   1.7       wiz     struct uvif *v;
    118   1.1    brezak 
    119   1.1    brezak     v = &uvifs[vifi];
    120   1.1    brezak     for (r = routing_table; r != NULL; r = r->rt_next) {
    121   1.1    brezak 	if (r->rt_metric != UNREACHABLE &&
    122   1.1    brezak 	    !VIFM_ISSET(vifi, r->rt_children)) {
    123   1.1    brezak 	    VIFM_SET(vifi, r->rt_children);
    124   1.1    brezak 	    r->rt_dominants   [vifi] = 0;
    125   1.1    brezak 	    r->rt_subordinates[vifi] = 0;
    126   1.1    brezak 	    if (v->uv_neighbors == NULL) {
    127   1.1    brezak 		VIFM_SET(vifi, r->rt_leaves);
    128   1.1    brezak 		r->rt_leaf_timers[vifi] = 0;
    129   1.1    brezak 	    }
    130   1.1    brezak 	    else {
    131   1.1    brezak 		VIFM_CLR(vifi, r->rt_leaves);
    132   1.1    brezak 		r->rt_leaf_timers[vifi] = LEAF_CONFIRMATION_TIME;
    133   1.1    brezak 		r->rt_flags |= RTF_LEAF_TIMING;
    134   1.1    brezak 	    }
    135   1.3   mycroft 	    update_table_entry(r);
    136   1.1    brezak 	}
    137   1.1    brezak     }
    138   1.1    brezak }
    139   1.1    brezak 
    140   1.1    brezak 
    141   1.1    brezak /*
    142   1.1    brezak  * A vif has gone down -- expire all routes that have that vif as parent,
    143   1.1    brezak  * and update the children bitmaps in all other route entries to take into
    144   1.1    brezak  * account the failed vif.
    145   1.1    brezak  */
    146   1.3   mycroft void
    147   1.7       wiz delete_vif_from_routes(vifi_t vifi)
    148   1.1    brezak {
    149   1.7       wiz     struct rtentry *r;
    150   1.1    brezak 
    151   1.1    brezak     for (r = routing_table; r != NULL; r = r->rt_next) {
    152   1.1    brezak 	if (r->rt_metric != UNREACHABLE) {
    153   1.1    brezak 	    if (vifi == r->rt_parent) {
    154   1.3   mycroft 		del_table_entry(r, 0, DEL_ALL_ROUTES);
    155   1.1    brezak 		r->rt_timer    = ROUTE_EXPIRE_TIME;
    156   1.1    brezak 		r->rt_metric   = UNREACHABLE;
    157   1.1    brezak 		r->rt_flags   |= RTF_CHANGED;
    158   1.1    brezak 		routes_changed = TRUE;
    159   1.1    brezak 	    }
    160   1.1    brezak 	    else if (VIFM_ISSET(vifi, r->rt_children)) {
    161   1.1    brezak 		VIFM_CLR(vifi, r->rt_children);
    162   1.1    brezak 		VIFM_CLR(vifi, r->rt_leaves);
    163   1.1    brezak 		r->rt_subordinates[vifi] = 0;
    164   1.1    brezak 		r->rt_leaf_timers [vifi] = 0;
    165   1.3   mycroft 		update_table_entry(r);
    166   1.1    brezak 	    }
    167   1.1    brezak 	    else {
    168   1.1    brezak 		r->rt_dominants[vifi] = 0;
    169   1.1    brezak 	    }
    170   1.1    brezak 	}
    171   1.1    brezak     }
    172   1.1    brezak }
    173   1.1    brezak 
    174   1.1    brezak 
    175   1.1    brezak /*
    176   1.1    brezak  * A neighbor has failed or become unreachable.  If that neighbor was
    177   1.1    brezak  * considered a dominant or subordinate router in any route entries,
    178   1.1    brezak  * take appropriate action.
    179   1.1    brezak  */
    180   1.3   mycroft void
    181   1.7       wiz delete_neighbor_from_routes(u_int32_t addr, vifi_t vifi)
    182   1.1    brezak {
    183   1.7       wiz     struct rtentry *r;
    184   1.7       wiz     struct uvif *v;
    185   1.1    brezak 
    186   1.1    brezak     v = &uvifs[vifi];
    187   1.1    brezak     for (r = routing_table; r != NULL; r = r->rt_next) {
    188   1.1    brezak 	if (r->rt_metric != UNREACHABLE) {
    189   1.1    brezak 	    if (r->rt_dominants[vifi] == addr) {
    190   1.1    brezak 		VIFM_SET(vifi, r->rt_children);
    191   1.1    brezak 		r->rt_dominants   [vifi] = 0;
    192   1.1    brezak 		r->rt_subordinates[vifi] = 0;
    193   1.1    brezak 		if (v->uv_neighbors == NULL) {
    194   1.1    brezak 		    VIFM_SET(vifi, r->rt_leaves);
    195   1.1    brezak 		    r->rt_leaf_timers[vifi] = 0;
    196   1.1    brezak 		}
    197   1.1    brezak 		else {
    198   1.1    brezak 		    VIFM_CLR(vifi, r->rt_leaves);
    199   1.1    brezak 		    r->rt_leaf_timers[vifi] = LEAF_CONFIRMATION_TIME;
    200   1.1    brezak 		    r->rt_flags |= RTF_LEAF_TIMING;
    201   1.1    brezak 		}
    202   1.3   mycroft 		update_table_entry(r);
    203   1.1    brezak 	    }
    204   1.1    brezak 	    else if (r->rt_subordinates[vifi] == addr) {
    205   1.1    brezak 		r->rt_subordinates[vifi] = 0;
    206   1.1    brezak 		if (v->uv_neighbors == NULL) {
    207   1.1    brezak 		    VIFM_SET(vifi, r->rt_leaves);
    208   1.3   mycroft 		    update_table_entry(r);
    209   1.1    brezak 		}
    210   1.1    brezak 		else {
    211   1.1    brezak 		    r->rt_leaf_timers[vifi] = LEAF_CONFIRMATION_TIME;
    212   1.1    brezak 		    r->rt_flags |= RTF_LEAF_TIMING;
    213   1.1    brezak 		}
    214   1.1    brezak 	    }
    215   1.1    brezak 	    else if (v->uv_neighbors == NULL &&
    216   1.1    brezak 		     r->rt_leaf_timers[vifi] != 0) {
    217   1.1    brezak 		VIFM_SET(vifi, r->rt_leaves);
    218   1.1    brezak 		r->rt_leaf_timers[vifi] = 0;
    219   1.3   mycroft 		update_table_entry(r);
    220   1.1    brezak 	    }
    221   1.1    brezak 	}
    222   1.1    brezak     }
    223   1.1    brezak }
    224   1.1    brezak 
    225   1.1    brezak 
    226   1.1    brezak /*
    227   1.1    brezak  * Prepare for a sequence of ordered route updates by initializing a pointer
    228   1.1    brezak  * to the start of the routing table.  The pointer is used to remember our
    229   1.1    brezak  * position in the routing table in order to avoid searching from the
    230   1.1    brezak  * beginning for each update; this relies on having the route reports in
    231   1.1    brezak  * a single message be in the same order as the route entries in the routing
    232   1.1    brezak  * table.
    233   1.1    brezak  */
    234   1.3   mycroft void
    235   1.7       wiz start_route_updates(void)
    236   1.1    brezak {
    237   1.3   mycroft     rtp = RT_ADDR;
    238   1.1    brezak }
    239   1.1    brezak 
    240   1.1    brezak 
    241   1.1    brezak /*
    242   1.1    brezak  * Starting at the route entry following the one to which 'rtp' points,
    243   1.1    brezak  * look for a route entry matching the specified origin and mask.  If a
    244   1.1    brezak  * match is found, return TRUE and leave 'rtp' pointing at the found entry.
    245   1.1    brezak  * If no match is found, return FALSE and leave 'rtp' pointing to the route
    246   1.1    brezak  * entry preceding the point at which the new origin should be inserted.
    247   1.1    brezak  * This code is optimized for the normal case in which the first entry to
    248   1.1    brezak  * be examined is the matching entry.
    249   1.1    brezak  */
    250   1.3   mycroft static int
    251   1.7       wiz find_route(u_int32_t origin, u_int32_t mask)
    252   1.1    brezak {
    253   1.7       wiz     struct rtentry *r;
    254   1.1    brezak 
    255   1.1    brezak     r = rtp->rt_next;
    256   1.1    brezak     while (r != NULL) {
    257   1.1    brezak 	if (origin == r->rt_origin && mask == r->rt_originmask) {
    258   1.1    brezak 	    rtp = r;
    259   1.1    brezak 	    return (TRUE);
    260   1.1    brezak 	}
    261   1.3   mycroft 	if (ntohl(mask) < ntohl(r->rt_originmask) ||
    262   1.1    brezak 	    (mask == r->rt_originmask &&
    263   1.3   mycroft 	     ntohl(origin) < ntohl(r->rt_origin))) {
    264   1.1    brezak 	    rtp = r;
    265   1.1    brezak 	    r = r->rt_next;
    266   1.1    brezak 	}
    267   1.1    brezak 	else break;
    268   1.1    brezak     }
    269   1.1    brezak     return (FALSE);
    270   1.1    brezak }
    271   1.1    brezak 
    272   1.1    brezak /*
    273   1.1    brezak  * Create a new routing table entry for the specified origin and link it into
    274   1.1    brezak  * the routing table.  The shared variable 'rtp' is assumed to point to the
    275   1.1    brezak  * routing entry after which the new one should be inserted.  It is left
    276   1.1    brezak  * pointing to the new entry.
    277   1.1    brezak  *
    278   1.1    brezak  * Only the origin, originmask, originwidth and flags fields are initialized
    279   1.6     soren  * in the new route entry; the caller is responsible for filling in the rest.
    280   1.1    brezak  */
    281   1.3   mycroft static void
    282   1.7       wiz create_route(u_int32_t origin, u_int32_t mask)
    283   1.1    brezak {
    284   1.7       wiz     struct rtentry *r;
    285   1.1    brezak 
    286   1.3   mycroft     if ((r = (struct rtentry *) malloc(sizeof(struct rtentry) +
    287   1.3   mycroft 				       (2 * numvifs * sizeof(u_int32_t)) +
    288   1.5   mycroft 				       (numvifs * sizeof(u_int)))) == NULL) {
    289   1.9       wiz 	logit(LOG_ERR, 0, "ran out of memory");	/* fatal */
    290  1.12  christos 	return;
    291   1.1    brezak     }
    292   1.1    brezak     r->rt_origin     = origin;
    293   1.1    brezak     r->rt_originmask = mask;
    294   1.1    brezak     if      (((char *)&mask)[3] != 0) r->rt_originwidth = 4;
    295   1.1    brezak     else if (((char *)&mask)[2] != 0) r->rt_originwidth = 3;
    296   1.1    brezak     else if (((char *)&mask)[1] != 0) r->rt_originwidth = 2;
    297   1.1    brezak     else                              r->rt_originwidth = 1;
    298   1.1    brezak     r->rt_flags        = 0;
    299   1.3   mycroft     r->rt_dominants    = (u_int32_t *)(r + 1);
    300   1.3   mycroft     r->rt_subordinates = (u_int32_t *)(r->rt_dominants + numvifs);
    301   1.5   mycroft     r->rt_leaf_timers  = (u_int *)(r->rt_subordinates + numvifs);
    302   1.3   mycroft     r->rt_groups       = NULL;
    303   1.1    brezak 
    304   1.1    brezak     r->rt_next = rtp->rt_next;
    305   1.1    brezak     rtp->rt_next = r;
    306   1.3   mycroft     r->rt_prev = rtp;
    307   1.3   mycroft     if (r->rt_next != NULL)
    308   1.3   mycroft       (r->rt_next)->rt_prev = r;
    309   1.3   mycroft     else
    310   1.3   mycroft       rt_end = r;
    311   1.1    brezak     rtp = r;
    312   1.1    brezak     ++nroutes;
    313   1.1    brezak }
    314   1.1    brezak 
    315   1.1    brezak 
    316   1.1    brezak /*
    317   1.1    brezak  * Discard the routing table entry following the one to which 'prev_r' points.
    318   1.1    brezak  */
    319   1.3   mycroft static void
    320   1.7       wiz discard_route(struct rtentry *prev_r)
    321   1.1    brezak {
    322   1.7       wiz     struct rtentry *r;
    323   1.1    brezak 
    324   1.1    brezak     r = prev_r->rt_next;
    325   1.1    brezak     prev_r->rt_next = r->rt_next;
    326   1.3   mycroft     if (prev_r->rt_next != NULL)
    327   1.3   mycroft       (prev_r->rt_next)->rt_prev = prev_r;
    328   1.3   mycroft     else
    329   1.3   mycroft       rt_end = prev_r;
    330   1.1    brezak     free((char *)r);
    331   1.1    brezak     --nroutes;
    332   1.1    brezak }
    333   1.1    brezak 
    334   1.1    brezak 
    335   1.1    brezak /*
    336   1.1    brezak  * Process a route report for a single origin, creating or updating the
    337   1.1    brezak  * corresponding routing table entry if necessary.  'src' is either the
    338   1.1    brezak  * address of a neighboring router from which the report arrived, or zero
    339   1.1    brezak  * to indicate a change of status of one of our own interfaces.
    340   1.1    brezak  */
    341   1.3   mycroft void
    342   1.7       wiz update_route(u_int32_t origin, u_int32_t mask, u_int metric, u_int32_t src,
    343   1.7       wiz 	     vifi_t vifi)
    344   1.1    brezak {
    345   1.7       wiz     struct rtentry *r;
    346   1.5   mycroft     u_int adj_metric;
    347   1.1    brezak 
    348   1.1    brezak     /*
    349   1.1    brezak      * Compute an adjusted metric, taking into account the cost of the
    350   1.1    brezak      * subnet or tunnel over which the report arrived, and normalizing
    351   1.1    brezak      * all unreachable/poisoned metrics into a single value.
    352   1.1    brezak      */
    353   1.1    brezak     if (src != 0 && (metric < 1 || metric >= 2*UNREACHABLE)) {
    354   1.9       wiz 	logit(LOG_WARNING, 0,
    355   1.1    brezak 	    "%s reports out-of-range metric %u for origin %s",
    356  1.11       dsl 	    inet_fmt(src), metric,
    357  1.11       dsl 	    inet_fmts(origin, mask));
    358   1.1    brezak 	return;
    359   1.1    brezak     }
    360   1.1    brezak     adj_metric = metric + uvifs[vifi].uv_metric;
    361   1.1    brezak     if (adj_metric > UNREACHABLE) adj_metric = UNREACHABLE;
    362   1.1    brezak 
    363   1.1    brezak     /*
    364   1.1    brezak      * Look up the reported origin in the routing table.
    365   1.1    brezak      */
    366   1.1    brezak     if (!find_route(origin, mask)) {
    367   1.1    brezak 	/*
    368   1.1    brezak 	 * Not found.
    369   1.1    brezak 	 * Don't create a new entry if the report says it's unreachable,
    370   1.1    brezak 	 * or if the reported origin and mask are invalid.
    371   1.1    brezak 	 */
    372   1.1    brezak 	if (adj_metric == UNREACHABLE) {
    373   1.1    brezak 	    return;
    374   1.1    brezak 	}
    375   1.1    brezak 	if (src != 0 && !inet_valid_subnet(origin, mask)) {
    376   1.9       wiz 	    logit(LOG_WARNING, 0,
    377   1.1    brezak 		"%s reports an invalid origin (%s) and/or mask (%08x)",
    378  1.11       dsl 		inet_fmt(src),
    379  1.11       dsl 		inet_fmt(origin), ntohl(mask));
    380   1.1    brezak 	    return;
    381   1.1    brezak 	}
    382   1.1    brezak 
    383   1.1    brezak 	/*
    384   1.3   mycroft 	 * OK, create the new routing entry.  'rtp' will be left pointing
    385   1.3   mycroft 	 * to the new entry.
    386   1.1    brezak 	 */
    387   1.3   mycroft 	create_route(origin, mask);
    388   1.1    brezak 
    389   1.1    brezak 	/*
    390   1.3   mycroft 	 * Now "steal away" any sources that belong under this route
    391   1.3   mycroft 	 * by deleting any cache entries they might have created
    392   1.3   mycroft 	 * and allowing the kernel to re-request them.
    393   1.1    brezak 	 */
    394   1.3   mycroft 	steal_sources(rtp);
    395   1.1    brezak 
    396   1.1    brezak 	rtp->rt_metric = UNREACHABLE;	/* temporary; updated below */
    397   1.1    brezak     }
    398   1.1    brezak 
    399   1.1    brezak     /*
    400   1.1    brezak      * We now have a routing entry for the reported origin.  Update it?
    401   1.1    brezak      */
    402   1.1    brezak     r = rtp;
    403   1.1    brezak     if (r->rt_metric == UNREACHABLE) {
    404   1.1    brezak 	/*
    405   1.1    brezak 	 * The routing entry is for a formerly-unreachable or new origin.
    406   1.1    brezak 	 * If the report claims reachability, update the entry to use
    407   1.1    brezak 	 * the reported route.
    408   1.1    brezak 	 */
    409   1.1    brezak 	if (adj_metric == UNREACHABLE)
    410   1.1    brezak 	    return;
    411   1.1    brezak 
    412   1.1    brezak 	r->rt_parent   = vifi;
    413   1.1    brezak 	init_children_and_leaves(r, vifi);
    414   1.3   mycroft 
    415   1.1    brezak 	r->rt_gateway  = src;
    416   1.1    brezak 	r->rt_timer    = 0;
    417   1.1    brezak 	r->rt_metric   = adj_metric;
    418   1.1    brezak 	r->rt_flags   |= RTF_CHANGED;
    419   1.1    brezak 	routes_changed = TRUE;
    420   1.3   mycroft 	update_table_entry(r);
    421   1.1    brezak     }
    422   1.1    brezak     else if (src == r->rt_gateway) {
    423   1.1    brezak 	/*
    424   1.1    brezak 	 * The report has come either from the interface directly-connected
    425   1.1    brezak 	 * to the origin subnet (src and r->rt_gateway both equal zero) or
    426   1.1    brezak 	 * from the gateway we have chosen as the best first-hop gateway back
    427   1.1    brezak 	 * towards the origin (src and r->rt_gateway not equal zero).  Reset
    428   1.1    brezak 	 * the route timer and, if the reported metric has changed, update
    429   1.1    brezak 	 * our entry accordingly.
    430   1.1    brezak 	 */
    431   1.1    brezak 	r->rt_timer = 0;
    432   1.1    brezak 	if (adj_metric == r->rt_metric)
    433   1.1    brezak 	    return;
    434   1.1    brezak 
    435   1.1    brezak 	if (adj_metric == UNREACHABLE) {
    436   1.3   mycroft 	    del_table_entry(r, 0, DEL_ALL_ROUTES);
    437   1.1    brezak 	    r->rt_timer = ROUTE_EXPIRE_TIME;
    438   1.1    brezak 	}
    439   1.1    brezak 	else if (adj_metric < r->rt_metric) {
    440   1.1    brezak 	    if (init_children_and_leaves(r, vifi)) {
    441   1.3   mycroft 		update_table_entry(r);
    442   1.1    brezak 	    }
    443   1.1    brezak 	}
    444   1.1    brezak 	r->rt_metric   = adj_metric;
    445   1.1    brezak 	r->rt_flags   |= RTF_CHANGED;
    446   1.1    brezak 	routes_changed = TRUE;
    447   1.1    brezak     }
    448   1.1    brezak     else if (src == 0 ||
    449   1.3   mycroft 	     (r->rt_gateway != 0 &&
    450   1.3   mycroft 	      (adj_metric < r->rt_metric ||
    451   1.3   mycroft 	       (adj_metric == r->rt_metric &&
    452   1.5   mycroft 		(ntohl(src) < ntohl(r->rt_gateway) ||
    453   1.5   mycroft 		 r->rt_timer >= ROUTE_SWITCH_TIME))))) {
    454   1.1    brezak 	/*
    455   1.1    brezak 	 * The report is for an origin we consider reachable; the report
    456   1.1    brezak 	 * comes either from one of our own interfaces or from a gateway
    457   1.1    brezak 	 * other than the one we have chosen as the best first-hop gateway
    458   1.1    brezak 	 * back towards the origin.  If the source of the update is one of
    459   1.1    brezak 	 * our own interfaces, or if the origin is not a directly-connected
    460   1.1    brezak 	 * subnet and the reported metric for that origin is better than
    461   1.1    brezak 	 * what our routing entry says, update the entry to use the new
    462   1.1    brezak 	 * gateway and metric.  We also switch gateways if the reported
    463   1.1    brezak 	 * metric is the same as the one in the route entry and the gateway
    464   1.5   mycroft 	 * associated with the route entry has not been heard from recently,
    465   1.5   mycroft 	 * or if the metric is the same but the reporting gateway has a lower
    466   1.5   mycroft 	 * IP address than the gateway associated with the route entry.
    467   1.1    brezak 	 * Did you get all that?
    468   1.1    brezak 	 */
    469   1.1    brezak 	if (r->rt_parent != vifi || adj_metric < r->rt_metric) {
    470   1.5   mycroft 	    /*
    471   1.5   mycroft 	     * XXX Why do we do this if we are just changing the metric?
    472   1.5   mycroft 	     */
    473   1.1    brezak 	    r->rt_parent = vifi;
    474   1.1    brezak 	    if (init_children_and_leaves(r, vifi)) {
    475   1.3   mycroft 		update_table_entry(r);
    476   1.1    brezak 	    }
    477   1.1    brezak 	}
    478   1.1    brezak 	r->rt_gateway  = src;
    479   1.1    brezak 	r->rt_timer    = 0;
    480   1.1    brezak 	r->rt_metric   = adj_metric;
    481   1.1    brezak 	r->rt_flags   |= RTF_CHANGED;
    482   1.1    brezak 	routes_changed = TRUE;
    483   1.1    brezak     }
    484   1.1    brezak     else if (vifi != r->rt_parent) {
    485   1.1    brezak 	/*
    486   1.1    brezak 	 * The report came from a vif other than the route's parent vif.
    487   1.1    brezak 	 * Update the children and leaf info, if necessary.
    488   1.1    brezak 	 */
    489   1.1    brezak 	if (VIFM_ISSET(vifi, r->rt_children)) {
    490   1.1    brezak 	    /*
    491   1.1    brezak 	     * Vif is a child vif for this route.
    492   1.1    brezak 	     */
    493   1.1    brezak 	    if (metric  < r->rt_metric ||
    494   1.3   mycroft 		(metric == r->rt_metric &&
    495   1.3   mycroft 		 ntohl(src) < ntohl(uvifs[vifi].uv_lcl_addr))) {
    496   1.1    brezak 		/*
    497   1.1    brezak 		 * Neighbor has lower metric to origin (or has same metric
    498   1.1    brezak 		 * and lower IP address) -- it becomes the dominant router,
    499   1.1    brezak 		 * and vif is no longer a child for me.
    500   1.1    brezak 		 */
    501   1.1    brezak 		VIFM_CLR(vifi, r->rt_children);
    502   1.1    brezak 		VIFM_CLR(vifi, r->rt_leaves);
    503   1.1    brezak 		r->rt_dominants   [vifi] = src;
    504   1.1    brezak 		r->rt_subordinates[vifi] = 0;
    505   1.1    brezak 		r->rt_leaf_timers [vifi] = 0;
    506   1.3   mycroft 		update_table_entry(r);
    507   1.1    brezak 	    }
    508   1.1    brezak 	    else if (metric > UNREACHABLE) {	/* "poisoned reverse" */
    509   1.1    brezak 		/*
    510   1.1    brezak 		 * Neighbor considers this vif to be on path to route's
    511   1.1    brezak 		 * origin; if no subordinate recorded, record this neighbor
    512   1.1    brezak 		 * as subordinate and clear the leaf flag.
    513   1.1    brezak 		 */
    514   1.1    brezak 		if (r->rt_subordinates[vifi] == 0) {
    515   1.1    brezak 		    VIFM_CLR(vifi, r->rt_leaves);
    516   1.1    brezak 		    r->rt_subordinates[vifi] = src;
    517   1.1    brezak 		    r->rt_leaf_timers [vifi] = 0;
    518   1.3   mycroft 		    update_table_entry(r);
    519   1.1    brezak 		}
    520   1.1    brezak 	    }
    521   1.1    brezak 	    else if (src == r->rt_subordinates[vifi]) {
    522   1.1    brezak 		/*
    523   1.1    brezak 		 * Current subordinate no longer considers this vif to be on
    524   1.1    brezak 		 * path to route's origin; it is no longer a subordinate
    525   1.1    brezak 		 * router, and we set the leaf confirmation timer to give
    526   1.1    brezak 		 * us time to hear from other subordinates.
    527   1.1    brezak 		 */
    528   1.1    brezak 		r->rt_subordinates[vifi] = 0;
    529   1.1    brezak 		if (uvifs[vifi].uv_neighbors == NULL ||
    530   1.1    brezak 		    uvifs[vifi].uv_neighbors->al_next == NULL) {
    531   1.1    brezak 		    VIFM_SET(vifi, r->rt_leaves);
    532   1.3   mycroft 		    update_table_entry(r);
    533   1.1    brezak 		}
    534   1.1    brezak 		else {
    535   1.1    brezak 		    r->rt_leaf_timers [vifi] = LEAF_CONFIRMATION_TIME;
    536   1.1    brezak 		    r->rt_flags |= RTF_LEAF_TIMING;
    537   1.1    brezak 		}
    538   1.1    brezak 	    }
    539   1.1    brezak 
    540   1.1    brezak 	}
    541   1.1    brezak 	else if (src == r->rt_dominants[vifi] &&
    542   1.3   mycroft 		 (metric  > r->rt_metric ||
    543   1.3   mycroft 		  (metric == r->rt_metric &&
    544   1.3   mycroft 		   ntohl(src) > ntohl(uvifs[vifi].uv_lcl_addr)))) {
    545   1.1    brezak 	    /*
    546   1.1    brezak 	     * Current dominant no longer has a lower metric to origin
    547   1.1    brezak 	     * (or same metric and lower IP address); we adopt the vif
    548   1.1    brezak 	     * as our own child.
    549   1.1    brezak 	     */
    550   1.1    brezak 	    VIFM_SET(vifi, r->rt_children);
    551   1.1    brezak 	    r->rt_dominants  [vifi] = 0;
    552   1.1    brezak 	    if (metric > UNREACHABLE) {
    553   1.1    brezak 		r->rt_subordinates[vifi] = src;
    554   1.1    brezak 	    }
    555   1.1    brezak 	    else if (uvifs[vifi].uv_neighbors == NULL ||
    556   1.1    brezak 		     uvifs[vifi].uv_neighbors->al_next == NULL) {
    557   1.1    brezak 		VIFM_SET(vifi, r->rt_leaves);
    558   1.1    brezak 	    }
    559   1.1    brezak 	    else {
    560   1.1    brezak 		r->rt_leaf_timers[vifi] = LEAF_CONFIRMATION_TIME;
    561   1.1    brezak 		r->rt_flags |= RTF_LEAF_TIMING;
    562   1.1    brezak 	    }
    563   1.3   mycroft 	    update_table_entry(r);
    564   1.1    brezak 	}
    565   1.1    brezak     }
    566   1.1    brezak }
    567   1.1    brezak 
    568   1.1    brezak 
    569   1.1    brezak /*
    570   1.1    brezak  * On every timer interrupt, advance the timer in each routing entry.
    571   1.1    brezak  */
    572   1.3   mycroft void
    573   1.7       wiz age_routes(void)
    574   1.1    brezak {
    575   1.7       wiz     struct rtentry *r;
    576   1.7       wiz     struct rtentry *prev_r;
    577   1.7       wiz     vifi_t vifi;
    578   1.1    brezak 
    579   1.3   mycroft     for (prev_r = RT_ADDR, r = routing_table;
    580   1.1    brezak 	 r != NULL;
    581   1.1    brezak 	 prev_r = r, r = r->rt_next) {
    582   1.1    brezak 
    583   1.1    brezak 	if ((r->rt_timer += TIMER_INTERVAL) < ROUTE_EXPIRE_TIME) {
    584   1.1    brezak 	    /*
    585   1.1    brezak 	     * Route is still good; see if any leaf timers need to be
    586   1.1    brezak 	     * advanced.
    587   1.1    brezak 	     */
    588   1.1    brezak 	    if (r->rt_flags & RTF_LEAF_TIMING) {
    589   1.1    brezak 		r->rt_flags &= ~RTF_LEAF_TIMING;
    590   1.1    brezak 		for (vifi = 0; vifi < numvifs; ++vifi) {
    591   1.1    brezak 		    if (r->rt_leaf_timers[vifi] != 0) {
    592   1.1    brezak 			/*
    593   1.1    brezak 			 * Unlike other timers, leaf timers decrement.
    594   1.1    brezak 			 */
    595   1.1    brezak 			if ((r->rt_leaf_timers[vifi] -= TIMER_INTERVAL) == 0){
    596   1.3   mycroft #ifdef NOTYET
    597   1.3   mycroft 			    /* If the vif is a physical leaf but has neighbors,
    598   1.3   mycroft 			     * it is not a tree leaf.  If I am a leaf, then no
    599   1.3   mycroft 			     * interface with neighbors is a tree leaf. */
    600   1.3   mycroft 			    if (!(((uvifs[vifi].uv_flags & VIFF_LEAF) ||
    601   1.3   mycroft 				   (vifs_with_neighbors == 1)) &&
    602   1.3   mycroft 				  (uvifs[vifi].uv_neighbors != NULL))) {
    603   1.3   mycroft #endif
    604   1.3   mycroft 				VIFM_SET(vifi, r->rt_leaves);
    605   1.3   mycroft 				update_table_entry(r);
    606   1.3   mycroft #ifdef NOTYET
    607   1.3   mycroft 			    }
    608   1.3   mycroft #endif
    609   1.1    brezak 			}
    610   1.1    brezak 			else {
    611   1.1    brezak 			    r->rt_flags |= RTF_LEAF_TIMING;
    612   1.1    brezak 			}
    613   1.1    brezak 		    }
    614   1.1    brezak 		}
    615   1.1    brezak 	    }
    616   1.1    brezak 	}
    617   1.1    brezak 	else if (r->rt_timer >= ROUTE_DISCARD_TIME) {
    618   1.1    brezak 	    /*
    619   1.1    brezak 	     * Time to garbage-collect the route entry.
    620   1.1    brezak 	     */
    621   1.3   mycroft 	    del_table_entry(r, 0, DEL_ALL_ROUTES);
    622   1.1    brezak 	    discard_route(prev_r);
    623   1.1    brezak 	    r = prev_r;
    624   1.1    brezak 	}
    625   1.1    brezak 	else if (r->rt_metric != UNREACHABLE) {
    626   1.1    brezak 	    /*
    627   1.1    brezak 	     * Time to expire the route entry.  If the gateway is zero,
    628   1.1    brezak 	     * i.e., it is a route to a directly-connected subnet, just
    629   1.1    brezak 	     * set the timer back to zero; such routes expire only when
    630   1.1    brezak 	     * the interface to the subnet goes down.
    631   1.1    brezak 	     */
    632   1.1    brezak 	    if (r->rt_gateway == 0) {
    633   1.1    brezak 		r->rt_timer = 0;
    634   1.3   mycroft 	    }
    635   1.1    brezak 	    else {
    636   1.3   mycroft 		del_table_entry(r, 0, DEL_ALL_ROUTES);
    637   1.1    brezak 		r->rt_metric   = UNREACHABLE;
    638   1.1    brezak 		r->rt_flags   |= RTF_CHANGED;
    639   1.1    brezak 		routes_changed = TRUE;
    640   1.1    brezak 	    }
    641   1.1    brezak 	}
    642   1.1    brezak     }
    643   1.1    brezak }
    644   1.1    brezak 
    645   1.1    brezak 
    646   1.1    brezak /*
    647   1.1    brezak  * Mark all routes as unreachable.  This function is called only from
    648   1.1    brezak  * hup() in preparation for informing all neighbors that we are going
    649   1.1    brezak  * off the air.  For consistency, we ought also to delete all reachable
    650   1.1    brezak  * route entries from the kernel, but since we are about to exit we rely
    651   1.1    brezak  * on the kernel to do its own cleanup -- no point in making all those
    652   1.1    brezak  * expensive kernel calls now.
    653   1.1    brezak  */
    654   1.3   mycroft void
    655   1.7       wiz expire_all_routes(void)
    656   1.1    brezak {
    657   1.7       wiz     struct rtentry *r;
    658   1.1    brezak 
    659   1.1    brezak     for (r = routing_table; r != NULL; r = r->rt_next) {
    660   1.1    brezak 	r->rt_metric   = UNREACHABLE;
    661   1.1    brezak 	r->rt_flags   |= RTF_CHANGED;
    662   1.1    brezak 	routes_changed = TRUE;
    663   1.1    brezak     }
    664   1.1    brezak }
    665   1.1    brezak 
    666   1.1    brezak 
    667   1.1    brezak /*
    668   1.3   mycroft  * Delete all the routes in the routing table.
    669   1.3   mycroft  */
    670   1.3   mycroft void
    671   1.7       wiz free_all_routes(void)
    672   1.3   mycroft {
    673   1.7       wiz     struct rtentry *r;
    674   1.3   mycroft 
    675   1.3   mycroft     r = RT_ADDR;
    676   1.3   mycroft 
    677   1.3   mycroft     while (r->rt_next)
    678   1.3   mycroft 	discard_route(r);
    679   1.3   mycroft }
    680   1.3   mycroft 
    681   1.3   mycroft 
    682   1.3   mycroft /*
    683   1.1    brezak  * Process an incoming neighbor probe message.
    684   1.1    brezak  */
    685   1.3   mycroft void
    686   1.7       wiz accept_probe(u_int32_t src, u_int32_t dst, char *p, int datalen,
    687   1.7       wiz 	     u_int32_t level)
    688   1.1    brezak {
    689   1.1    brezak     vifi_t vifi;
    690   1.1    brezak 
    691   1.1    brezak     if ((vifi = find_vif(src, dst)) == NO_VIF) {
    692   1.9       wiz 	logit(LOG_INFO, 0,
    693  1.11       dsl     	    "ignoring probe from non-neighbor %s", inet_fmt(src));
    694   1.1    brezak 	return;
    695   1.1    brezak     }
    696   1.1    brezak 
    697   1.5   mycroft     update_neighbor(vifi, src, DVMRP_PROBE, p, datalen, level);
    698   1.1    brezak }
    699   1.1    brezak 
    700   1.2    brezak struct newrt {
    701   1.3   mycroft 	u_int32_t mask;
    702   1.3   mycroft 	u_int32_t origin;
    703   1.2    brezak 	int metric;
    704   1.2    brezak 	int pad;
    705   1.2    brezak };
    706   1.2    brezak 
    707   1.5   mycroft static int
    708   1.7       wiz compare_rts(const void *rt1, const void *rt2)
    709   1.7       wiz {
    710  1.13     lukem     const struct newrt *r1 = (const struct newrt *)rt1;
    711  1.13     lukem     const struct newrt *r2 = (const struct newrt *)rt2;
    712   1.7       wiz     u_int32_t m1 = ntohl(r1->mask);
    713   1.7       wiz     u_int32_t m2 = ntohl(r2->mask);
    714   1.7       wiz     u_int32_t o1, o2;
    715   1.2    brezak 
    716   1.2    brezak     if (m1 > m2)
    717   1.3   mycroft 	return (-1);
    718   1.3   mycroft     if (m1 < m2)
    719   1.2    brezak 	return (1);
    720   1.2    brezak 
    721   1.2    brezak     /* masks are equal */
    722   1.2    brezak     o1 = ntohl(r1->origin);
    723   1.2    brezak     o2 = ntohl(r2->origin);
    724   1.2    brezak     if (o1 > o2)
    725   1.3   mycroft 	return (-1);
    726   1.3   mycroft     if (o1 < o2)
    727   1.2    brezak 	return (1);
    728   1.2    brezak     return (0);
    729   1.2    brezak }
    730   1.1    brezak 
    731   1.1    brezak /*
    732   1.1    brezak  * Process an incoming route report message.
    733   1.1    brezak  */
    734   1.3   mycroft void
    735   1.7       wiz accept_report(u_int32_t src, u_int32_t dst, char *p, int datalen,
    736   1.7       wiz 	      u_int32_t level)
    737   1.1    brezak {
    738   1.1    brezak     vifi_t vifi;
    739   1.7       wiz     int width, i, nrt = 0;
    740   1.1    brezak     int metric;
    741   1.3   mycroft     u_int32_t mask;
    742   1.3   mycroft     u_int32_t origin;
    743   1.2    brezak     struct newrt rt[4096];
    744   1.1    brezak 
    745   1.1    brezak     if ((vifi = find_vif(src, dst)) == NO_VIF) {
    746   1.9       wiz 	logit(LOG_INFO, 0,
    747  1.11       dsl     	    "ignoring route report from non-neighbor %s", inet_fmt(src));
    748   1.1    brezak 	return;
    749   1.1    brezak     }
    750   1.1    brezak 
    751   1.3   mycroft     if (!update_neighbor(vifi, src, DVMRP_REPORT, NULL, 0, level))
    752   1.1    brezak 	return;
    753   1.1    brezak 
    754   1.2    brezak     if (datalen > 2*4096) {
    755   1.9       wiz 	logit(LOG_INFO, 0,
    756   1.2    brezak     	    "ignoring oversize (%d bytes) route report from %s",
    757  1.11       dsl 	    datalen, inet_fmt(src));
    758   1.2    brezak 	return;
    759   1.2    brezak     }
    760   1.1    brezak 
    761   1.1    brezak     while (datalen > 0) {	/* Loop through per-mask lists. */
    762   1.3   mycroft 
    763   1.1    brezak 	if (datalen < 3) {
    764   1.9       wiz 	    logit(LOG_WARNING, 0,
    765   1.3   mycroft 		"received truncated route report from %s",
    766  1.11       dsl 		inet_fmt(src));
    767   1.1    brezak 	    return;
    768   1.1    brezak 	}
    769   1.3   mycroft 	((u_char *)&mask)[0] = 0xff;            width = 1;
    770   1.3   mycroft 	if ((((u_char *)&mask)[1] = *p++) != 0) width = 2;
    771   1.3   mycroft 	if ((((u_char *)&mask)[2] = *p++) != 0) width = 3;
    772   1.3   mycroft 	if ((((u_char *)&mask)[3] = *p++) != 0) width = 4;
    773   1.5   mycroft 	if (!inet_valid_mask(ntohl(mask))) {
    774   1.9       wiz 	    logit(LOG_WARNING, 0,
    775   1.5   mycroft 		"%s reports bogus netmask 0x%08x (%s)",
    776  1.11       dsl 		inet_fmt(src), ntohl(mask),
    777  1.11       dsl 		inet_fmt(mask));
    778   1.5   mycroft 	    return;
    779   1.5   mycroft 	}
    780   1.1    brezak 	datalen -= 3;
    781   1.1    brezak 
    782   1.1    brezak 	do {			/* Loop through (origin, metric) pairs */
    783   1.1    brezak 	    if (datalen < width + 1) {
    784   1.9       wiz 		logit(LOG_WARNING, 0,
    785   1.3   mycroft 		    "received truncated route report from %s",
    786  1.11       dsl 		    inet_fmt(src));
    787   1.1    brezak 		return;
    788   1.1    brezak 	    }
    789   1.1    brezak 	    origin = 0;
    790   1.1    brezak 	    for (i = 0; i < width; ++i)
    791   1.1    brezak 		((char *)&origin)[i] = *p++;
    792   1.1    brezak 	    metric = *p++;
    793   1.1    brezak 	    datalen -= width + 1;
    794   1.2    brezak 	    rt[nrt].mask   = mask;
    795   1.2    brezak 	    rt[nrt].origin = origin;
    796   1.3   mycroft 	    rt[nrt].metric = (metric & 0x7f);
    797   1.2    brezak 	    ++nrt;
    798   1.1    brezak 	} while (!(metric & 0x80));
    799   1.1    brezak     }
    800   1.5   mycroft 
    801   1.2    brezak     qsort((char*)rt, nrt, sizeof(rt[0]), compare_rts);
    802   1.2    brezak     start_route_updates();
    803   1.3   mycroft     /*
    804   1.3   mycroft      * If the last entry is default, change mask from 0xff000000 to 0
    805   1.3   mycroft      */
    806   1.3   mycroft     if (rt[nrt-1].origin == 0)
    807   1.3   mycroft 	rt[nrt-1].mask = 0;
    808   1.3   mycroft 
    809   1.9       wiz     logit(LOG_DEBUG, 0, "Updating %d routes from %s to %s", nrt,
    810  1.11       dsl 		inet_fmt(src), inet_fmt(dst));
    811   1.5   mycroft     for (i = 0; i < nrt; ++i) {
    812   1.5   mycroft 	if (i != 0 && rt[i].origin == rt[i-1].origin &&
    813   1.5   mycroft 		      rt[i].mask == rt[i-1].mask) {
    814   1.9       wiz 	    logit(LOG_WARNING, 0, "%s reports duplicate route for %s",
    815  1.11       dsl 		inet_fmt(src),
    816  1.11       dsl 		inet_fmts(rt[i].origin, rt[i].mask));
    817   1.5   mycroft 	    continue;
    818   1.5   mycroft 	}
    819   1.3   mycroft 	update_route(rt[i].origin, rt[i].mask, rt[i].metric,
    820   1.3   mycroft 		     src, vifi);
    821   1.5   mycroft     }
    822   1.1    brezak 
    823   1.1    brezak     if (routes_changed && !delay_change_reports)
    824   1.1    brezak 	report_to_all_neighbors(CHANGED_ROUTES);
    825   1.1    brezak }
    826   1.1    brezak 
    827   1.1    brezak 
    828   1.1    brezak /*
    829   1.1    brezak  * Send a route report message to destination 'dst', via virtual interface
    830   1.1    brezak  * 'vifi'.  'which_routes' specifies ALL_ROUTES or CHANGED_ROUTES.
    831   1.1    brezak  */
    832   1.3   mycroft void
    833   1.7       wiz report(int which_routes, vifi_t vifi, u_int32_t dst)
    834   1.1    brezak {
    835   1.7       wiz     struct rtentry *r;
    836   1.7       wiz     char *p;
    837   1.7       wiz     int i;
    838   1.5   mycroft     int datalen = 0;
    839   1.5   mycroft     int width = 0;
    840   1.5   mycroft     u_int32_t mask = 0;
    841   1.3   mycroft     u_int32_t src;
    842   1.3   mycroft     u_int32_t nflags;
    843   1.1    brezak 
    844   1.1    brezak     src = uvifs[vifi].uv_lcl_addr;
    845   1.1    brezak 
    846   1.1    brezak     p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
    847   1.1    brezak 
    848   1.3   mycroft #ifdef NOTYET
    849   1.3   mycroft     /* If I'm not a leaf, but the neighbor is a leaf, only advertise default */
    850   1.3   mycroft     if ((vifs_with_neighbors != 1) && (uvifs[vifi].uv_flags & VIFF_LEAF)) {
    851   1.3   mycroft       *p++ = 0;       /* 0xff000000 mask */
    852   1.3   mycroft       *p++ = 0;
    853   1.3   mycroft       *p++ = 0;
    854   1.3   mycroft       *p++ = 0;       /* class A net 0.0.0.0 == default */
    855   1.3   mycroft       *p++ = 0x81;    /*XXX metric 1, is this safe? */
    856   1.3   mycroft       datalen += 5;
    857   1.3   mycroft       send_igmp(src, dst, IGMP_DVMRP, DVMRP_REPORT,
    858   1.3   mycroft                 htonl(MROUTED_LEVEL), datalen);
    859   1.3   mycroft       return;
    860   1.3   mycroft     }
    861   1.3   mycroft #endif
    862   1.3   mycroft 
    863   1.3   mycroft     nflags = (uvifs[vifi].uv_flags & VIFF_LEAF) ? 0 : LEAF_FLAGS;
    864   1.3   mycroft 
    865   1.3   mycroft     for (r = rt_end; r != RT_ADDR; r = r->rt_prev) {
    866   1.1    brezak 
    867   1.1    brezak 	if (which_routes == CHANGED_ROUTES && !(r->rt_flags & RTF_CHANGED))
    868   1.1    brezak 	    continue;
    869   1.1    brezak 
    870   1.1    brezak 	/*
    871   1.1    brezak 	 * If there is no room for this route in the current message,
    872   1.1    brezak 	 * send the message and start a new one.
    873   1.1    brezak 	 */
    874   1.1    brezak 	if (datalen + ((r->rt_originmask == mask) ?
    875   1.3   mycroft 		       (width + 1) :
    876   1.3   mycroft 		       (r->rt_originwidth + 4)) > MAX_DVMRP_DATA_LEN) {
    877   1.1    brezak 	    *(p-1) |= 0x80;
    878   1.1    brezak 	    send_igmp(src, dst, IGMP_DVMRP, DVMRP_REPORT,
    879   1.3   mycroft 		      htonl(MROUTED_LEVEL | nflags), datalen);
    880   1.1    brezak 
    881   1.1    brezak 	    p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
    882   1.1    brezak 	    datalen = 0;
    883   1.1    brezak 	    mask = 0;
    884   1.1    brezak 	}
    885   1.1    brezak 
    886   1.5   mycroft 	if (r->rt_originmask != mask || datalen == 0) {
    887   1.1    brezak 	    mask  = r->rt_originmask;
    888   1.1    brezak 	    width = r->rt_originwidth;
    889   1.1    brezak 	    if (datalen != 0) *(p-1) |= 0x80;
    890   1.1    brezak 	    *p++ = ((char *)&mask)[1];
    891   1.1    brezak 	    *p++ = ((char *)&mask)[2];
    892   1.1    brezak 	    *p++ = ((char *)&mask)[3];
    893   1.1    brezak 	    datalen += 3;
    894   1.1    brezak 	}
    895   1.1    brezak 
    896   1.1    brezak 	for (i = 0; i < width; ++i)
    897   1.1    brezak 	    *p++ = ((char *)&(r->rt_origin))[i];
    898   1.1    brezak 
    899   1.1    brezak 	*p++ = (r->rt_parent == vifi && r->rt_metric != UNREACHABLE) ?
    900   1.3   mycroft 	    (char)(r->rt_metric + UNREACHABLE) :  /* "poisoned reverse" */
    901   1.1    brezak 		(char)(r->rt_metric);
    902   1.1    brezak 
    903   1.1    brezak 	datalen += width + 1;
    904   1.1    brezak     }
    905   1.1    brezak 
    906   1.1    brezak     if (datalen != 0) {
    907   1.1    brezak 	*(p-1) |= 0x80;
    908   1.1    brezak 	send_igmp(src, dst, IGMP_DVMRP, DVMRP_REPORT,
    909   1.3   mycroft 		  htonl(MROUTED_LEVEL | nflags), datalen);
    910   1.1    brezak     }
    911   1.1    brezak }
    912   1.1    brezak 
    913   1.1    brezak 
    914   1.1    brezak /*
    915   1.1    brezak  * Send a route report message to all neighboring routers.
    916   1.1    brezak  * 'which_routes' specifies ALL_ROUTES or CHANGED_ROUTES.
    917   1.1    brezak  */
    918   1.3   mycroft void
    919   1.7       wiz report_to_all_neighbors(int which_routes)
    920   1.1    brezak {
    921   1.7       wiz     vifi_t vifi;
    922   1.7       wiz     struct uvif *v;
    923   1.7       wiz     struct rtentry *r;
    924   1.1    brezak     int routes_changed_before;
    925   1.1    brezak 
    926   1.1    brezak     /*
    927   1.1    brezak      * Remember the state of the global routes_changed flag before
    928   1.1    brezak      * generating the reports, and clear the flag.
    929   1.1    brezak      */
    930   1.1    brezak     routes_changed_before = routes_changed;
    931   1.1    brezak     routes_changed = FALSE;
    932   1.1    brezak 
    933   1.1    brezak 
    934   1.1    brezak     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
    935   1.1    brezak 	if (v->uv_neighbors != NULL) {
    936   1.1    brezak 	    report(which_routes, vifi,
    937   1.1    brezak 		   (v->uv_flags & VIFF_TUNNEL) ? v->uv_rmt_addr
    938   1.3   mycroft 		   : dvmrp_group);
    939   1.1    brezak 	}
    940   1.1    brezak     }
    941   1.1    brezak 
    942   1.1    brezak     /*
    943   1.1    brezak      * If there were changed routes before we sent the reports AND
    944   1.1    brezak      * if no new changes occurred while sending the reports, clear
    945   1.1    brezak      * the change flags in the individual route entries.  If changes
    946   1.1    brezak      * did occur while sending the reports, new reports will be
    947   1.1    brezak      * generated at the next timer interrupt.
    948   1.1    brezak      */
    949   1.1    brezak     if (routes_changed_before && !routes_changed) {
    950   1.1    brezak 	for (r = routing_table; r != NULL; r = r->rt_next) {
    951   1.1    brezak 	    r->rt_flags &= ~RTF_CHANGED;
    952   1.1    brezak 	}
    953   1.1    brezak     }
    954   1.1    brezak 
    955   1.1    brezak     /*
    956   1.1    brezak      * Set a flag to inhibit further reports of changed routes until the
    957   1.1    brezak      * next timer interrupt.  This is to alleviate update storms.
    958   1.1    brezak      */
    959   1.1    brezak     delay_change_reports = TRUE;
    960   1.2    brezak }
    961   1.2    brezak 
    962   1.2    brezak /*
    963   1.2    brezak  * Send a route report message to destination 'dst', via virtual interface
    964   1.2    brezak  * 'vifi'.  'which_routes' specifies ALL_ROUTES or CHANGED_ROUTES.
    965   1.2    brezak  */
    966   1.5   mycroft static int
    967   1.7       wiz report_chunk(struct rtentry *start_rt, vifi_t vifi, u_int32_t dst)
    968   1.2    brezak {
    969   1.7       wiz     struct rtentry *r;
    970   1.7       wiz     char *p;
    971   1.7       wiz     int i;
    972   1.7       wiz     int nrt = 0;
    973   1.5   mycroft     int datalen = 0;
    974   1.5   mycroft     int width = 0;
    975   1.5   mycroft     u_int32_t mask = 0;
    976   1.3   mycroft     u_int32_t src;
    977   1.3   mycroft     u_int32_t nflags;
    978   1.2    brezak 
    979   1.2    brezak     src = uvifs[vifi].uv_lcl_addr;
    980   1.2    brezak     p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
    981   1.2    brezak 
    982   1.3   mycroft     nflags = (uvifs[vifi].uv_flags & VIFF_LEAF) ? 0 : LEAF_FLAGS;
    983   1.3   mycroft 
    984   1.3   mycroft     for (r = start_rt; r != RT_ADDR; r = r->rt_prev) {
    985   1.3   mycroft 
    986   1.3   mycroft #ifdef NOTYET
    987   1.3   mycroft 	/* Don't send poisoned routes back to parents if I am a leaf */
    988   1.3   mycroft 	if ((vifs_with_neighbors == 1) && (r->rt_parent == vifi)
    989   1.3   mycroft 		&& (r->rt_metric > 1)) {
    990   1.3   mycroft 	    ++nrt;
    991   1.3   mycroft 	    continue;
    992   1.3   mycroft 	}
    993   1.3   mycroft #endif
    994   1.3   mycroft 
    995   1.2    brezak 	/*
    996   1.2    brezak 	 * If there is no room for this route in the current message,
    997   1.2    brezak 	 * send it & return how many routes we sent.
    998   1.2    brezak 	 */
    999   1.2    brezak 	if (datalen + ((r->rt_originmask == mask) ?
   1000   1.3   mycroft 		       (width + 1) :
   1001   1.3   mycroft 		       (r->rt_originwidth + 4)) > MAX_DVMRP_DATA_LEN) {
   1002   1.2    brezak 	    *(p-1) |= 0x80;
   1003   1.2    brezak 	    send_igmp(src, dst, IGMP_DVMRP, DVMRP_REPORT,
   1004   1.3   mycroft 		      htonl(MROUTED_LEVEL | nflags), datalen);
   1005   1.2    brezak 	    return (nrt);
   1006   1.2    brezak 	}
   1007   1.5   mycroft 	if (r->rt_originmask != mask || datalen == 0) {
   1008   1.2    brezak 	    mask  = r->rt_originmask;
   1009   1.2    brezak 	    width = r->rt_originwidth;
   1010   1.2    brezak 	    if (datalen != 0) *(p-1) |= 0x80;
   1011   1.2    brezak 	    *p++ = ((char *)&mask)[1];
   1012   1.2    brezak 	    *p++ = ((char *)&mask)[2];
   1013   1.2    brezak 	    *p++ = ((char *)&mask)[3];
   1014   1.2    brezak 	    datalen += 3;
   1015   1.2    brezak 	}
   1016   1.2    brezak 	for (i = 0; i < width; ++i)
   1017   1.2    brezak 	    *p++ = ((char *)&(r->rt_origin))[i];
   1018   1.2    brezak 
   1019   1.2    brezak 	*p++ = (r->rt_parent == vifi && r->rt_metric != UNREACHABLE) ?
   1020   1.3   mycroft 	    (char)(r->rt_metric + UNREACHABLE) :  /* "poisoned reverse" */
   1021   1.2    brezak 		(char)(r->rt_metric);
   1022   1.2    brezak 	++nrt;
   1023   1.2    brezak 	datalen += width + 1;
   1024   1.2    brezak     }
   1025   1.2    brezak     if (datalen != 0) {
   1026   1.2    brezak 	*(p-1) |= 0x80;
   1027   1.2    brezak 	send_igmp(src, dst, IGMP_DVMRP, DVMRP_REPORT,
   1028   1.3   mycroft 		  htonl(MROUTED_LEVEL | nflags), datalen);
   1029   1.2    brezak     }
   1030   1.2    brezak     return (nrt);
   1031   1.2    brezak }
   1032   1.2    brezak 
   1033   1.2    brezak /*
   1034   1.2    brezak  * send the next chunk of our routing table to all neighbors.
   1035   1.3   mycroft  * return the length of the smallest chunk we sent out.
   1036   1.2    brezak  */
   1037   1.3   mycroft int
   1038   1.7       wiz report_next_chunk(void)
   1039   1.2    brezak {
   1040   1.7       wiz     vifi_t vifi;
   1041   1.7       wiz     struct uvif *v;
   1042   1.7       wiz     struct rtentry *sr;
   1043   1.7       wiz     int i, n = 0, min = 20000;
   1044   1.2    brezak     static int start_rt;
   1045   1.2    brezak 
   1046   1.2    brezak     if (nroutes <= 0)
   1047   1.2    brezak 	return (0);
   1048   1.2    brezak 
   1049   1.2    brezak     /*
   1050   1.2    brezak      * find this round's starting route.
   1051   1.2    brezak      */
   1052   1.3   mycroft     for (sr = rt_end, i = start_rt; --i >= 0; ) {
   1053   1.3   mycroft 	sr = sr->rt_prev;
   1054   1.3   mycroft 	if (sr == RT_ADDR)
   1055   1.3   mycroft 	    sr = rt_end;
   1056   1.2    brezak     }
   1057   1.3   mycroft 
   1058   1.2    brezak     /*
   1059   1.2    brezak      * send one chunk of routes starting at this round's start to
   1060   1.2    brezak      * all our neighbors.
   1061   1.2    brezak      */
   1062   1.2    brezak     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
   1063   1.3   mycroft 	if ((v->uv_neighbors != NULL)
   1064   1.3   mycroft #ifdef NOTYET
   1065   1.3   mycroft 	&& !(v->uv_flags & VIFF_LEAF)
   1066   1.3   mycroft #endif
   1067   1.3   mycroft 		) {
   1068   1.2    brezak 	    n = report_chunk(sr, vifi,
   1069   1.3   mycroft 			     (v->uv_flags & VIFF_TUNNEL) ? v->uv_rmt_addr
   1070   1.3   mycroft 			     : dvmrp_group);
   1071   1.3   mycroft 	    if (n < min)
   1072   1.3   mycroft 		min = n;
   1073   1.2    brezak 	}
   1074   1.2    brezak     }
   1075   1.3   mycroft     if (min == 20000)
   1076   1.3   mycroft 	min = 0;	/* Neighborless router didn't send any routes */
   1077   1.3   mycroft 
   1078   1.3   mycroft     n = min;
   1079   1.9       wiz     logit(LOG_INFO, 0, "update %d starting at %d of %d",
   1080   1.3   mycroft 	n, (nroutes - start_rt), nroutes);
   1081   1.3   mycroft 
   1082   1.2    brezak     start_rt = (start_rt + n) % nroutes;
   1083   1.2    brezak     return (n);
   1084   1.1    brezak }
   1085   1.1    brezak 
   1086   1.1    brezak 
   1087   1.1    brezak /*
   1088   1.1    brezak  * Print the contents of the routing table on file 'fp'.
   1089   1.1    brezak  */
   1090   1.3   mycroft void
   1091   1.7       wiz dump_routes(FILE *fp)
   1092   1.1    brezak {
   1093   1.7       wiz     struct rtentry *r;
   1094   1.7       wiz     vifi_t i;
   1095   1.3   mycroft 
   1096   1.1    brezak 
   1097   1.1    brezak     fprintf(fp,
   1098   1.3   mycroft 	    "Multicast Routing Table (%u %s)\n%s\n",
   1099   1.3   mycroft 	    nroutes, (nroutes == 1) ? "entry" : "entries",
   1100   1.3   mycroft 	    " Origin-Subnet      From-Gateway    Metric Tmr In-Vif  Out-Vifs");
   1101   1.1    brezak 
   1102   1.1    brezak     for (r = routing_table; r != NULL; r = r->rt_next) {
   1103   1.1    brezak 
   1104   1.3   mycroft 	fprintf(fp, " %-18s %-15s ",
   1105  1.11       dsl 		inet_fmts(r->rt_origin, r->rt_originmask),
   1106  1.11       dsl 		(r->rt_gateway == 0) ? "" : inet_fmt(r->rt_gateway));
   1107   1.1    brezak 
   1108   1.1    brezak 	fprintf(fp, (r->rt_metric == UNREACHABLE) ? "  NR " : "%4u ",
   1109   1.1    brezak 		r->rt_metric);
   1110   1.1    brezak 
   1111   1.3   mycroft 	fprintf(fp, "  %3u %3u   ", r->rt_timer, r->rt_parent);
   1112   1.1    brezak 
   1113   1.1    brezak 	for (i = 0; i < numvifs; ++i) {
   1114   1.1    brezak 	    if (VIFM_ISSET(i, r->rt_children)) {
   1115   1.1    brezak 		fprintf(fp, " %u%c",
   1116   1.1    brezak 			i, VIFM_ISSET(i, r->rt_leaves) ? '*' : ' ');
   1117   1.1    brezak 	    }
   1118   1.1    brezak 	}
   1119   1.1    brezak 	fprintf(fp, "\n");
   1120   1.1    brezak     }
   1121   1.1    brezak     fprintf(fp, "\n");
   1122   1.3   mycroft }
   1123   1.3   mycroft 
   1124   1.3   mycroft struct rtentry *
   1125   1.7       wiz determine_route(u_int32_t src)
   1126   1.3   mycroft {
   1127   1.3   mycroft     struct rtentry *rt;
   1128   1.3   mycroft 
   1129   1.3   mycroft     for (rt = routing_table; rt != NULL; rt = rt->rt_next) {
   1130   1.3   mycroft 	if (rt->rt_origin == (src & rt->rt_originmask))
   1131   1.3   mycroft 	    break;
   1132   1.3   mycroft     }
   1133   1.3   mycroft     return rt;
   1134   1.1    brezak }
   1135