Home | History | Annotate | Line # | Download | only in mrouted
prune.c revision 1.17.28.1
      1  1.17.28.1       jym /*	$NetBSD: prune.c,v 1.17.28.1 2009/05/13 19:20:30 jym Exp $	*/
      2        1.2   thorpej 
      3        1.1   mycroft /*
      4        1.1   mycroft  * The mrouted program is covered by the license in the accompanying file
      5        1.1   mycroft  * named "LICENSE".  Use of the mrouted program represents acceptance of
      6        1.1   mycroft  * the terms and conditions listed in that file.
      7        1.1   mycroft  *
      8        1.1   mycroft  * The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
      9        1.1   mycroft  * Leland Stanford Junior University.
     10        1.1   mycroft  */
     11        1.1   mycroft 
     12        1.1   mycroft 
     13        1.1   mycroft #include "defs.h"
     14        1.1   mycroft 
     15        1.1   mycroft extern int cache_lifetime;
     16        1.1   mycroft extern int max_prune_lifetime;
     17        1.1   mycroft extern struct rtentry *routing_table;
     18        1.1   mycroft 
     19        1.3   mycroft extern int phys_vif;
     20        1.3   mycroft 
     21        1.1   mycroft /*
     22        1.1   mycroft  * dither cache lifetime to obtain a value between x and 2*x
     23        1.1   mycroft  */
     24       1.15    itojun #define CACHE_LIFETIME(x) ((x) + (arc4random() % (x)))
     25        1.1   mycroft 
     26        1.1   mycroft #define CHK_GS(x, y) {	\
     27        1.1   mycroft 		switch(x) { \
     28        1.1   mycroft 			case 2:	\
     29        1.1   mycroft 			case 4:	\
     30        1.1   mycroft 			case 8:	\
     31        1.1   mycroft 			case 16: \
     32        1.1   mycroft 			case 32: \
     33        1.1   mycroft 			case 64: \
     34        1.1   mycroft 			case 128: \
     35       1.16       mrg 			/*case 256:*/ y = 1; \
     36        1.1   mycroft 				  break; \
     37        1.1   mycroft 			default:  y = 0; \
     38        1.1   mycroft 		} \
     39        1.1   mycroft 	}
     40        1.1   mycroft 
     41        1.1   mycroft struct gtable *kernel_table;		/* ptr to list of kernel grp entries*/
     42        1.1   mycroft static struct gtable *kernel_no_route;	/* list of grp entries w/o routes   */
     43        1.1   mycroft struct gtable *gtp;			/* pointer for kernel rt entries    */
     44        1.1   mycroft unsigned int kroutes;			/* current number of cache entries  */
     45        1.1   mycroft 
     46        1.1   mycroft /****************************************************************************
     47        1.1   mycroft                        Functions that are local to prune.c
     48        1.1   mycroft ****************************************************************************/
     49        1.9       wiz static void		prun_add_ttls(struct gtable *gt);
     50        1.9       wiz static int		pruning_neighbor(vifi_t vifi, u_int32_t addr);
     51        1.9       wiz static int		can_mtrace(vifi_t vifi, u_int32_t addr);
     52        1.9       wiz static struct ptable *	find_prune_entry(u_int32_t vr, struct ptable *pt);
     53        1.9       wiz static void		expire_prune(vifi_t vifi, struct gtable *gt);
     54        1.9       wiz static void		send_prune(struct gtable *gt);
     55        1.9       wiz static void		send_graft(struct gtable *gt);
     56        1.9       wiz static void		send_graft_ack(u_int32_t src, u_int32_t dst,
     57        1.9       wiz 				       u_int32_t origin, u_int32_t grp);
     58        1.9       wiz static void		update_kernel(struct gtable *g);
     59  1.17.28.1       jym static const char *	scaletime(u_long t);
     60        1.1   mycroft 
     61        1.1   mycroft /*
     62        1.1   mycroft  * Updates the ttl values for each vif.
     63        1.1   mycroft  */
     64        1.1   mycroft static void
     65        1.9       wiz prun_add_ttls(struct gtable *gt)
     66        1.1   mycroft {
     67        1.1   mycroft     struct uvif *v;
     68        1.1   mycroft     vifi_t vifi;
     69        1.1   mycroft 
     70        1.1   mycroft     for (vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v) {
     71        1.1   mycroft 	if (VIFM_ISSET(vifi, gt->gt_grpmems))
     72        1.1   mycroft 	    gt->gt_ttls[vifi] = v->uv_threshold;
     73        1.1   mycroft 	else
     74        1.1   mycroft 	    gt->gt_ttls[vifi] = 0;
     75        1.1   mycroft     }
     76        1.1   mycroft }
     77        1.1   mycroft 
     78        1.1   mycroft /*
     79        1.1   mycroft  * checks for scoped multicast addresses
     80        1.1   mycroft  */
     81        1.1   mycroft #define GET_SCOPE(gt) { \
     82        1.9       wiz 	vifi_t _i; \
     83        1.1   mycroft 	if ((ntohl((gt)->gt_mcastgrp) & 0xff000000) == 0xef000000) \
     84        1.1   mycroft 	    for (_i = 0; _i < numvifs; _i++) \
     85        1.1   mycroft 		if (scoped_addr(_i, (gt)->gt_mcastgrp)) \
     86        1.1   mycroft 		    VIFM_SET(_i, (gt)->gt_scope); \
     87        1.1   mycroft 	}
     88        1.1   mycroft 
     89        1.1   mycroft int
     90        1.9       wiz scoped_addr(vifi_t vifi, u_int32_t addr)
     91        1.1   mycroft {
     92        1.1   mycroft     struct vif_acl *acl;
     93        1.1   mycroft 
     94        1.1   mycroft     for (acl = uvifs[vifi].uv_acl; acl; acl = acl->acl_next)
     95        1.1   mycroft 	if ((addr & acl->acl_mask) == acl->acl_addr)
     96        1.1   mycroft 	    return 1;
     97        1.1   mycroft 
     98        1.1   mycroft     return 0;
     99        1.1   mycroft }
    100        1.1   mycroft 
    101        1.1   mycroft /*
    102        1.1   mycroft  * Determine if mcastgrp has a listener on vifi
    103        1.1   mycroft  */
    104        1.1   mycroft int
    105        1.9       wiz grplst_mem(vifi_t vifi, u_int32_t mcastgrp)
    106        1.1   mycroft {
    107        1.9       wiz     struct listaddr *g;
    108        1.9       wiz     struct uvif *v;
    109        1.1   mycroft 
    110        1.1   mycroft     v = &uvifs[vifi];
    111        1.1   mycroft 
    112        1.1   mycroft     for (g = v->uv_groups; g != NULL; g = g->al_next)
    113        1.1   mycroft 	if (mcastgrp == g->al_addr)
    114        1.1   mycroft 	    return 1;
    115        1.1   mycroft 
    116        1.1   mycroft     return 0;
    117        1.1   mycroft }
    118        1.1   mycroft 
    119        1.1   mycroft /*
    120        1.1   mycroft  * Finds the group entry with the specified source and netmask.
    121        1.1   mycroft  * If netmask is 0, it uses the route's netmask.
    122        1.1   mycroft  *
    123        1.1   mycroft  * Returns TRUE if found a match, and the global variable gtp is left
    124        1.1   mycroft  * pointing to entry before the found entry.
    125        1.1   mycroft  * Returns FALSE if no exact match found, gtp is left pointing to before
    126        1.1   mycroft  * the entry in question belongs, or is NULL if the it belongs at the
    127        1.1   mycroft  * head of the list.
    128        1.1   mycroft  */
    129        1.1   mycroft int
    130        1.9       wiz find_src_grp(u_int32_t src, u_int32_t mask, u_int32_t grp)
    131        1.1   mycroft {
    132        1.1   mycroft     struct gtable *gt;
    133        1.1   mycroft 
    134        1.1   mycroft     gtp = NULL;
    135        1.1   mycroft     gt = kernel_table;
    136        1.1   mycroft     while (gt != NULL) {
    137        1.1   mycroft 	if (grp == gt->gt_mcastgrp &&
    138        1.1   mycroft 	    (mask ? (gt->gt_route->rt_origin == src &&
    139        1.1   mycroft 		     gt->gt_route->rt_originmask == mask) :
    140        1.1   mycroft 		    ((src & gt->gt_route->rt_originmask) ==
    141        1.1   mycroft 		     gt->gt_route->rt_origin)))
    142        1.1   mycroft 	    return TRUE;
    143        1.1   mycroft 	if (ntohl(grp) > ntohl(gt->gt_mcastgrp) ||
    144        1.1   mycroft 	    (grp == gt->gt_mcastgrp &&
    145        1.1   mycroft 	     (ntohl(mask) < ntohl(gt->gt_route->rt_originmask) ||
    146        1.1   mycroft 	      (mask == gt->gt_route->rt_originmask &&
    147        1.1   mycroft 	       (ntohl(src) > ntohl(gt->gt_route->rt_origin)))))) {
    148        1.1   mycroft 	    gtp = gt;
    149        1.1   mycroft 	    gt = gt->gt_gnext;
    150        1.1   mycroft 	}
    151        1.1   mycroft 	else break;
    152        1.1   mycroft     }
    153        1.1   mycroft     return FALSE;
    154        1.1   mycroft }
    155        1.1   mycroft 
    156        1.1   mycroft /*
    157        1.1   mycroft  * Check if the neighbor supports pruning
    158        1.1   mycroft  */
    159        1.1   mycroft static int
    160        1.9       wiz pruning_neighbor(vifi_t vifi, u_int32_t addr)
    161        1.1   mycroft {
    162        1.1   mycroft     struct listaddr *n = neighbor_info(vifi, addr);
    163        1.1   mycroft     int vers;
    164        1.1   mycroft 
    165        1.1   mycroft     if (n == NULL)
    166        1.1   mycroft 	return 0;
    167        1.1   mycroft 
    168        1.1   mycroft     if (n->al_flags & NF_PRUNE)
    169        1.1   mycroft 	return 1;
    170        1.1   mycroft 
    171        1.1   mycroft     /*
    172        1.1   mycroft      * Versions from 3.0 to 3.4 relied on the version number to identify
    173        1.1   mycroft      * that they could handle pruning.
    174        1.1   mycroft      */
    175        1.1   mycroft     vers = NBR_VERS(n);
    176        1.1   mycroft     return (vers >= 0x0300 && vers <= 0x0304);
    177        1.1   mycroft }
    178        1.1   mycroft 
    179        1.1   mycroft /*
    180        1.1   mycroft  * Can the neighbor in question handle multicast traceroute?
    181        1.1   mycroft  */
    182        1.1   mycroft static int
    183        1.9       wiz can_mtrace(vifi_t vifi, u_int32_t addr)
    184        1.1   mycroft {
    185        1.1   mycroft     struct listaddr *n = neighbor_info(vifi, addr);
    186        1.1   mycroft     int vers;
    187        1.1   mycroft 
    188        1.1   mycroft     if (n == NULL)
    189        1.1   mycroft 	return 0;
    190        1.1   mycroft 
    191        1.1   mycroft     if (n->al_flags & NF_MTRACE)
    192        1.1   mycroft 	return 1;
    193        1.1   mycroft 
    194        1.1   mycroft     /*
    195        1.1   mycroft      * Versions 3.3 and 3.4 relied on the version number to identify
    196        1.1   mycroft      * that they could handle traceroute.
    197        1.1   mycroft      */
    198        1.1   mycroft     vers = NBR_VERS(n);
    199        1.1   mycroft     return (vers >= 0x0303 && vers <= 0x0304);
    200        1.1   mycroft }
    201        1.1   mycroft 
    202        1.1   mycroft /*
    203        1.1   mycroft  * Returns the prune entry of the router, or NULL if none exists
    204        1.1   mycroft  */
    205        1.1   mycroft static struct ptable *
    206        1.9       wiz find_prune_entry(u_int32_t vr, struct ptable *pt)
    207        1.1   mycroft {
    208        1.1   mycroft     while (pt) {
    209        1.1   mycroft 	if (pt->pt_router == vr)
    210        1.1   mycroft 	    return pt;
    211        1.1   mycroft 	pt = pt->pt_next;
    212        1.1   mycroft     }
    213        1.1   mycroft 
    214        1.1   mycroft     return NULL;
    215        1.1   mycroft }
    216        1.1   mycroft 
    217        1.1   mycroft /*
    218        1.1   mycroft  * Send a prune message to the dominant router for
    219        1.1   mycroft  * this source.
    220        1.1   mycroft  *
    221        1.1   mycroft  * Record an entry that a prune was sent for this group
    222        1.1   mycroft  */
    223        1.1   mycroft static void
    224        1.9       wiz send_prune(struct gtable *gt)
    225        1.1   mycroft {
    226        1.1   mycroft     struct ptable *pt;
    227        1.1   mycroft     char *p;
    228        1.1   mycroft     int i;
    229        1.1   mycroft     int datalen;
    230        1.1   mycroft     u_int32_t src;
    231        1.1   mycroft     u_int32_t dst;
    232        1.1   mycroft     u_int32_t tmp;
    233        1.1   mycroft 
    234        1.1   mycroft     /* Don't process any prunes if router is not pruning */
    235        1.1   mycroft     if (pruning == 0)
    236        1.1   mycroft 	return;
    237        1.1   mycroft 
    238        1.1   mycroft     /* Can't process a prune if we don't have an associated route */
    239        1.1   mycroft     if (gt->gt_route == NULL)
    240        1.1   mycroft 	return;
    241        1.1   mycroft 
    242        1.1   mycroft     /* Don't send a prune to a non-pruning router */
    243        1.1   mycroft     if (!pruning_neighbor(gt->gt_route->rt_parent, gt->gt_route->rt_gateway))
    244        1.1   mycroft 	return;
    245        1.1   mycroft 
    246        1.1   mycroft     /*
    247        1.1   mycroft      * sends a prune message to the router upstream.
    248        1.1   mycroft      */
    249        1.1   mycroft     src = uvifs[gt->gt_route->rt_parent].uv_lcl_addr;
    250        1.1   mycroft     dst = gt->gt_route->rt_gateway;
    251        1.1   mycroft 
    252        1.1   mycroft     p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
    253        1.1   mycroft     datalen = 0;
    254        1.1   mycroft 
    255        1.1   mycroft     /*
    256        1.1   mycroft      * determine prune lifetime
    257        1.1   mycroft      */
    258        1.1   mycroft     gt->gt_prsent_timer = gt->gt_timer;
    259        1.1   mycroft     for (pt = gt->gt_pruntbl; pt; pt = pt->pt_next)
    260        1.1   mycroft 	if (pt->pt_timer < gt->gt_prsent_timer)
    261        1.1   mycroft 	    gt->gt_prsent_timer = pt->pt_timer;
    262        1.1   mycroft 
    263        1.1   mycroft     /*
    264        1.1   mycroft      * If we have a graft pending, cancel graft retransmission
    265        1.1   mycroft      */
    266        1.1   mycroft     gt->gt_grftsnt = 0;
    267        1.1   mycroft 
    268        1.1   mycroft     for (i = 0; i < 4; i++)
    269        1.1   mycroft 	*p++ = ((char *)&(gt->gt_route->rt_origin))[i];
    270        1.1   mycroft     for (i = 0; i < 4; i++)
    271        1.1   mycroft 	*p++ = ((char *)&(gt->gt_mcastgrp))[i];
    272        1.1   mycroft     tmp = htonl(gt->gt_prsent_timer);
    273        1.1   mycroft     for (i = 0; i < 4; i++)
    274        1.1   mycroft 	*p++ = ((char *)&(tmp))[i];
    275        1.1   mycroft     datalen += 12;
    276        1.1   mycroft 
    277        1.1   mycroft     send_igmp(src, dst, IGMP_DVMRP, DVMRP_PRUNE,
    278        1.1   mycroft 	      htonl(MROUTED_LEVEL), datalen);
    279        1.1   mycroft 
    280       1.11       wiz     logit(LOG_DEBUG, 0, "sent prune for (%s %s)/%d on vif %d to %s",
    281       1.14       dsl       inet_fmts(gt->gt_route->rt_origin, gt->gt_route->rt_originmask),
    282       1.14       dsl       inet_fmt(gt->gt_mcastgrp),
    283        1.1   mycroft       gt->gt_prsent_timer, gt->gt_route->rt_parent,
    284       1.14       dsl       inet_fmt(gt->gt_route->rt_gateway));
    285        1.1   mycroft }
    286        1.1   mycroft 
    287        1.1   mycroft /*
    288        1.1   mycroft  * a prune was sent upstream
    289        1.1   mycroft  * so, a graft has to be sent to annul the prune
    290        1.1   mycroft  * set up a graft timer so that if an ack is not
    291        1.1   mycroft  * heard within that time, another graft request
    292        1.1   mycroft  * is sent out.
    293        1.1   mycroft  */
    294        1.1   mycroft static void
    295        1.9       wiz send_graft(struct gtable *gt)
    296        1.1   mycroft {
    297        1.9       wiz     char *p;
    298        1.9       wiz     int i;
    299        1.1   mycroft     int datalen;
    300        1.1   mycroft     u_int32_t src;
    301        1.1   mycroft     u_int32_t dst;
    302        1.1   mycroft 
    303        1.1   mycroft     /* Can't send a graft without an associated route */
    304        1.1   mycroft     if (gt->gt_route == NULL)
    305        1.1   mycroft 	return;
    306        1.1   mycroft 
    307        1.1   mycroft     src = uvifs[gt->gt_route->rt_parent].uv_lcl_addr;
    308        1.1   mycroft     dst = gt->gt_route->rt_gateway;
    309        1.1   mycroft 
    310        1.1   mycroft     p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
    311        1.1   mycroft     datalen = 0;
    312        1.1   mycroft 
    313        1.1   mycroft     for (i = 0; i < 4; i++)
    314        1.1   mycroft 	*p++ = ((char *)&(gt->gt_route->rt_origin))[i];
    315        1.1   mycroft     for (i = 0; i < 4; i++)
    316        1.1   mycroft 	*p++ = ((char *)&(gt->gt_mcastgrp))[i];
    317        1.1   mycroft     datalen += 8;
    318        1.1   mycroft 
    319        1.1   mycroft     if (datalen != 0) {
    320        1.1   mycroft 	send_igmp(src, dst, IGMP_DVMRP, DVMRP_GRAFT,
    321        1.1   mycroft 		  htonl(MROUTED_LEVEL), datalen);
    322        1.1   mycroft     }
    323       1.11       wiz     logit(LOG_DEBUG, 0, "sent graft for (%s %s) to %s on vif %d",
    324       1.14       dsl 	inet_fmts(gt->gt_route->rt_origin, gt->gt_route->rt_originmask),
    325       1.14       dsl 	inet_fmt(gt->gt_mcastgrp),
    326       1.14       dsl 	inet_fmt(gt->gt_route->rt_gateway),
    327       1.13    itojun 	gt->gt_route->rt_parent);
    328        1.1   mycroft }
    329        1.1   mycroft 
    330        1.1   mycroft /*
    331        1.1   mycroft  * Send an ack that a graft was received
    332        1.1   mycroft  */
    333        1.1   mycroft static void
    334        1.9       wiz send_graft_ack(u_int32_t src, u_int32_t dst, u_int32_t origin, u_int32_t grp)
    335        1.1   mycroft {
    336        1.9       wiz     char *p;
    337        1.9       wiz     int i;
    338        1.1   mycroft     int datalen;
    339        1.1   mycroft 
    340        1.1   mycroft     p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
    341        1.1   mycroft     datalen = 0;
    342        1.1   mycroft 
    343        1.1   mycroft     for (i = 0; i < 4; i++)
    344        1.1   mycroft 	*p++ = ((char *)&(origin))[i];
    345        1.1   mycroft     for (i = 0; i < 4; i++)
    346        1.1   mycroft 	*p++ = ((char *)&(grp))[i];
    347        1.1   mycroft     datalen += 8;
    348        1.1   mycroft 
    349        1.1   mycroft     send_igmp(src, dst, IGMP_DVMRP, DVMRP_GRAFT_ACK,
    350        1.1   mycroft 	      htonl(MROUTED_LEVEL), datalen);
    351        1.1   mycroft 
    352       1.11       wiz     logit(LOG_DEBUG, 0, "sent graft ack for (%s, %s) to %s",
    353       1.14       dsl 	inet_fmt(origin), inet_fmt(grp),
    354       1.14       dsl 	inet_fmt(dst));
    355        1.1   mycroft }
    356        1.1   mycroft 
    357        1.1   mycroft /*
    358        1.1   mycroft  * Update the kernel cache with all the routes hanging off the group entry
    359        1.1   mycroft  */
    360        1.1   mycroft static void
    361        1.9       wiz update_kernel(struct gtable *g)
    362        1.1   mycroft {
    363        1.1   mycroft     struct stable *st;
    364        1.1   mycroft 
    365        1.1   mycroft     for (st = g->gt_srctbl; st; st = st->st_next)
    366        1.1   mycroft 	k_add_rg(st->st_origin, g);
    367        1.1   mycroft }
    368        1.1   mycroft 
    369        1.1   mycroft /****************************************************************************
    370        1.1   mycroft                           Functions that are used externally
    371        1.1   mycroft ****************************************************************************/
    372        1.1   mycroft 
    373        1.1   mycroft #ifdef SNMP
    374        1.1   mycroft #include <sys/types.h>
    375        1.1   mycroft #include "snmp.h"
    376        1.1   mycroft 
    377        1.1   mycroft /*
    378        1.1   mycroft  * Find a specific group entry in the group table
    379        1.1   mycroft  */
    380        1.1   mycroft struct gtable *
    381       1.12       wiz find_grp(u_long grp)
    382        1.1   mycroft {
    383        1.1   mycroft    struct gtable *gt;
    384        1.1   mycroft 
    385        1.1   mycroft    for (gt = kernel_table; gt; gt = gt->gt_gnext) {
    386        1.1   mycroft       if (ntohl(grp) < ntohl(gt->gt_mcastgrp))
    387        1.1   mycroft       	 break;
    388        1.1   mycroft       if (gt->gt_mcastgrp == grp)
    389        1.1   mycroft          return gt;
    390        1.1   mycroft    }
    391        1.1   mycroft    return NULL;
    392        1.1   mycroft }
    393        1.1   mycroft 
    394        1.1   mycroft /*
    395        1.1   mycroft  * Given a group entry and source, find the corresponding source table
    396        1.1   mycroft  * entry
    397        1.1   mycroft  */
    398        1.1   mycroft struct stable *
    399        1.9       wiz find_grp_src(struct gtable *gt, u_long src)
    400        1.1   mycroft {
    401        1.1   mycroft    struct stable *st;
    402        1.1   mycroft    u_long grp = gt->gt_mcastgrp;
    403        1.1   mycroft    struct gtable *gtcurr;
    404        1.1   mycroft 
    405        1.1   mycroft    for (gtcurr = gt; gtcurr->gt_mcastgrp == grp; gtcurr = gtcurr->gt_gnext) {
    406        1.1   mycroft       for (st = gtcurr->gt_srctbl; st; st = st->st_next)
    407        1.1   mycroft 	 if (st->st_origin == src)
    408        1.1   mycroft 	    return st;
    409        1.1   mycroft    }
    410        1.1   mycroft    return NULL;
    411        1.1   mycroft }
    412        1.1   mycroft 
    413        1.1   mycroft /*
    414        1.1   mycroft  * Find next entry > specification
    415        1.9       wiz  *
    416        1.9       wiz  * gtpp: ordered by group
    417        1.9       wiz  * stpp: ordered by source
    418        1.1   mycroft  */
    419        1.1   mycroft int
    420        1.9       wiz next_grp_src_mask(struct gtable **gtpp, struct stable **stpp, u_long grp,
    421        1.9       wiz 		  u_long src, u_long mask)
    422        1.1   mycroft {
    423        1.1   mycroft    struct gtable *gt, *gbest = NULL;
    424        1.1   mycroft    struct stable *st, *sbest = NULL;
    425        1.1   mycroft 
    426        1.1   mycroft    /* Find first group entry >= grp spec */
    427        1.1   mycroft    (*gtpp) = kernel_table;
    428        1.1   mycroft    while ((*gtpp) && ntohl((*gtpp)->gt_mcastgrp) < ntohl(grp))
    429        1.1   mycroft       (*gtpp)=(*gtpp)->gt_gnext;
    430        1.1   mycroft    if (!(*gtpp))
    431        1.1   mycroft       return 0; /* no more groups */
    432        1.1   mycroft 
    433        1.1   mycroft    for (gt = kernel_table; gt; gt=gt->gt_gnext) {
    434        1.1   mycroft       /* Since grps are ordered, we can stop when group changes from gbest */
    435        1.1   mycroft       if (gbest && gbest->gt_mcastgrp != gt->gt_mcastgrp)
    436        1.1   mycroft          break;
    437        1.1   mycroft       for (st = gt->gt_srctbl; st; st=st->st_next) {
    438        1.1   mycroft 
    439        1.1   mycroft          /* Among those entries > spec, find "lowest" one */
    440        1.1   mycroft          if (((ntohl(gt->gt_mcastgrp)> ntohl(grp))
    441        1.1   mycroft            || (ntohl(gt->gt_mcastgrp)==ntohl(grp)
    442        1.1   mycroft               && ntohl(st->st_origin)> ntohl(src))
    443        1.1   mycroft            || (ntohl(gt->gt_mcastgrp)==ntohl(grp)
    444        1.1   mycroft               && ntohl(st->st_origin)==src && 0xFFFFFFFF>ntohl(mask)))
    445        1.1   mycroft           && (!gbest
    446        1.1   mycroft            || (ntohl(gt->gt_mcastgrp)< ntohl(gbest->gt_mcastgrp))
    447        1.1   mycroft            || (ntohl(gt->gt_mcastgrp)==ntohl(gbest->gt_mcastgrp)
    448        1.1   mycroft               && ntohl(st->st_origin)< ntohl(sbest->st_origin)))) {
    449        1.1   mycroft                gbest = gt;
    450        1.1   mycroft                sbest = st;
    451        1.1   mycroft          }
    452        1.1   mycroft       }
    453        1.1   mycroft    }
    454        1.1   mycroft    (*gtpp) = gbest;
    455        1.1   mycroft    (*stpp) = sbest;
    456        1.1   mycroft    return (*gtpp)!=0;
    457        1.1   mycroft }
    458        1.1   mycroft 
    459        1.1   mycroft /*
    460        1.1   mycroft  * Ensure that sg contains current information for the given group,source.
    461        1.1   mycroft  * This is fetched from the kernel as a unit so that counts for the entry
    462        1.1   mycroft  * are consistent, i.e. packet and byte counts for the same entry are
    463        1.1   mycroft  * read at the same time.
    464        1.1   mycroft  */
    465        1.1   mycroft void
    466        1.9       wiz refresh_sg(struct sioc_sg_req *sg, struct gtable *gt, struct stable *st)
    467        1.1   mycroft {
    468        1.1   mycroft    static   int lastq = -1;
    469        1.1   mycroft 
    470        1.1   mycroft    if (quantum != lastq || sg->src.s_addr!=st->st_origin
    471        1.1   mycroft     || sg->grp.s_addr!=gt->gt_mcastgrp) {
    472        1.1   mycroft        lastq = quantum;
    473        1.1   mycroft        sg->src.s_addr = st->st_origin;
    474        1.1   mycroft        sg->grp.s_addr = gt->gt_mcastgrp;
    475        1.6       hwr        ioctl(igmp_socket, SIOCGETSGCNT, (char *)sg);
    476        1.1   mycroft    }
    477        1.1   mycroft }
    478        1.1   mycroft 
    479        1.1   mycroft /*
    480        1.1   mycroft  * Return pointer to a specific route entry.  This must be a separate
    481        1.1   mycroft  * function from find_route() which modifies rtp.
    482        1.1   mycroft  */
    483        1.1   mycroft struct rtentry *
    484        1.9       wiz snmp_find_route(u_long src, u_long mask)
    485        1.1   mycroft {
    486        1.9       wiz     struct rtentry *rt;
    487        1.1   mycroft 
    488        1.1   mycroft    for (rt = routing_table; rt; rt = rt->rt_next) {
    489        1.1   mycroft       if (src == rt->rt_origin && mask == rt->rt_originmask)
    490        1.1   mycroft          return rt;
    491        1.1   mycroft    }
    492        1.1   mycroft    return NULL;
    493        1.1   mycroft }
    494        1.1   mycroft 
    495        1.1   mycroft /*
    496        1.1   mycroft  * Find next route entry > specification
    497        1.1   mycroft  */
    498        1.1   mycroft int
    499        1.9       wiz next_route(struct rtentry **rtpp, u_long src, u_long mask)
    500        1.1   mycroft {
    501        1.1   mycroft    struct rtentry *rt, *rbest = NULL;
    502        1.1   mycroft 
    503        1.1   mycroft    /* Among all entries > spec, find "lowest" one in order */
    504        1.1   mycroft    for (rt = routing_table; rt; rt=rt->rt_next) {
    505        1.1   mycroft       if ((ntohl(rt->rt_origin) > ntohl(src)
    506        1.1   mycroft           || (ntohl(rt->rt_origin) == ntohl(src)
    507        1.1   mycroft              && ntohl(rt->rt_originmask) > ntohl(mask)))
    508        1.1   mycroft        && (!rbest || (ntohl(rt->rt_origin) < ntohl(rbest->rt_origin))
    509        1.1   mycroft           || (ntohl(rt->rt_origin) == ntohl(rbest->rt_origin)
    510        1.1   mycroft              && ntohl(rt->rt_originmask) < ntohl(rbest->rt_originmask))))
    511        1.1   mycroft                rbest = rt;
    512        1.1   mycroft    }
    513        1.1   mycroft    (*rtpp) = rbest;
    514        1.1   mycroft    return (*rtpp)!=0;
    515        1.1   mycroft }
    516        1.1   mycroft 
    517        1.1   mycroft /*
    518        1.1   mycroft  * Given a routing table entry, and a vifi, find the next vifi/entry
    519        1.9       wiz  *
    520        1.9       wiz  * vifi: vifi at which to start looking
    521        1.1   mycroft  */
    522        1.1   mycroft int
    523        1.9       wiz next_route_child(struct rtentry **rtpp, u_long src, u_long mask, vifi_t *vifi)
    524        1.1   mycroft {
    525        1.1   mycroft    struct rtentry *rt;
    526        1.1   mycroft 
    527        1.1   mycroft    /* Get (S,M) entry */
    528        1.1   mycroft    if (!((*rtpp) = snmp_find_route(src,mask)))
    529        1.1   mycroft       if (!next_route(rtpp, src, mask))
    530        1.1   mycroft          return 0;
    531        1.1   mycroft 
    532        1.1   mycroft    /* Continue until we get one with a valid next vif */
    533        1.1   mycroft    do {
    534        1.1   mycroft       for (; (*rtpp)->rt_children && *vifi<numvifs; (*vifi)++)
    535        1.1   mycroft          if (VIFM_ISSET(*vifi, (*rtpp)->rt_children))
    536        1.1   mycroft             return 1;
    537        1.1   mycroft       *vifi = 0;
    538        1.1   mycroft    } while( next_route(rtpp, (*rtpp)->rt_origin, (*rtpp)->rt_originmask) );
    539        1.1   mycroft 
    540        1.1   mycroft    return 0;
    541        1.1   mycroft }
    542        1.1   mycroft 
    543        1.1   mycroft /*
    544        1.1   mycroft  * Given a routing table entry, and a vifi, find the next entry
    545        1.1   mycroft  * equal to or greater than those
    546        1.9       wiz  *
    547        1.9       wiz  * vifi: vifi at which to start looking
    548        1.1   mycroft  */
    549        1.1   mycroft int
    550        1.9       wiz next_child(struct gtable **gtpp, struct stable **stpp, u_long grp, u_long src,
    551        1.9       wiz 	   u_long mask, vifi_t *vifi)
    552        1.1   mycroft {
    553        1.1   mycroft    struct stable *st;
    554        1.1   mycroft 
    555        1.1   mycroft    /* Get (G,S,M) entry */
    556        1.1   mycroft    if (mask!=0xFFFFFFFF
    557        1.1   mycroft     || !((*gtpp) = find_grp(grp))
    558        1.1   mycroft     || !((*stpp) = find_grp_src((*gtpp),src)))
    559        1.1   mycroft       if (!next_grp_src_mask(gtpp, stpp, grp, src, mask))
    560        1.1   mycroft          return 0;
    561        1.1   mycroft 
    562        1.1   mycroft    /* Continue until we get one with a valid next vif */
    563        1.1   mycroft    do {
    564        1.1   mycroft       for (; (*gtpp)->gt_route->rt_children && *vifi<numvifs; (*vifi)++)
    565        1.1   mycroft          if (VIFM_ISSET(*vifi, (*gtpp)->gt_route->rt_children))
    566        1.1   mycroft             return 1;
    567        1.1   mycroft       *vifi = 0;
    568        1.1   mycroft    } while (next_grp_src_mask(gtpp, stpp, (*gtpp)->gt_mcastgrp,
    569        1.1   mycroft 		(*stpp)->st_origin, 0xFFFFFFFF) );
    570        1.1   mycroft 
    571        1.1   mycroft    return 0;
    572        1.1   mycroft }
    573        1.1   mycroft #endif /* SNMP */
    574        1.1   mycroft 
    575        1.1   mycroft /*
    576        1.1   mycroft  * Initialize the kernel table structure
    577        1.1   mycroft  */
    578        1.1   mycroft void
    579        1.9       wiz init_ktable(void)
    580        1.1   mycroft {
    581        1.1   mycroft     kernel_table 	= NULL;
    582        1.1   mycroft     kernel_no_route	= NULL;
    583        1.1   mycroft     kroutes		= 0;
    584        1.1   mycroft }
    585        1.1   mycroft 
    586        1.1   mycroft /*
    587        1.1   mycroft  * Add a new table entry for (origin, mcastgrp)
    588        1.1   mycroft  */
    589        1.1   mycroft void
    590        1.9       wiz add_table_entry(u_int32_t origin, u_int32_t mcastgrp)
    591        1.1   mycroft {
    592        1.1   mycroft     struct rtentry *r;
    593        1.1   mycroft     struct gtable *gt,**gtnp,*prev_gt;
    594        1.1   mycroft     struct stable *st,**stnp;
    595        1.3   mycroft     vifi_t i;
    596        1.3   mycroft 
    597        1.3   mycroft #ifdef DEBUG_MFC
    598        1.3   mycroft     md_log(MD_MISS, origin, mcastgrp);
    599        1.3   mycroft #endif
    600        1.1   mycroft 
    601        1.1   mycroft     r = determine_route(origin);
    602        1.1   mycroft     prev_gt = NULL;
    603        1.1   mycroft     if (r == NULL) {
    604        1.1   mycroft 	/*
    605        1.1   mycroft 	 * Look for it on the no_route table; if it is found then
    606        1.1   mycroft 	 * it will be detected as a duplicate below.
    607        1.1   mycroft 	 */
    608        1.1   mycroft 	for (gt = kernel_no_route; gt; gt = gt->gt_next)
    609        1.1   mycroft 	    if (mcastgrp == gt->gt_mcastgrp &&
    610        1.1   mycroft 		gt->gt_srctbl && gt->gt_srctbl->st_origin == origin)
    611        1.1   mycroft 			break;
    612        1.1   mycroft 	gtnp = &kernel_no_route;
    613        1.1   mycroft     } else {
    614        1.1   mycroft 	gtnp = &r->rt_groups;
    615        1.1   mycroft 	while ((gt = *gtnp) != NULL) {
    616        1.1   mycroft 	    if (gt->gt_mcastgrp >= mcastgrp)
    617        1.1   mycroft 		break;
    618        1.1   mycroft 	    gtnp = &gt->gt_next;
    619        1.1   mycroft 	    prev_gt = gt;
    620        1.1   mycroft 	}
    621        1.1   mycroft     }
    622        1.1   mycroft 
    623        1.1   mycroft     if (gt == NULL || gt->gt_mcastgrp != mcastgrp) {
    624        1.1   mycroft 	gt = (struct gtable *)malloc(sizeof(struct gtable));
    625       1.17  christos 	if (gt == NULL) {
    626       1.11       wiz 	    logit(LOG_ERR, 0, "ran out of memory");
    627       1.17  christos 	    return;
    628       1.17  christos 	}
    629        1.1   mycroft 
    630        1.1   mycroft 	gt->gt_mcastgrp	    = mcastgrp;
    631        1.1   mycroft 	gt->gt_timer   	    = CACHE_LIFETIME(cache_lifetime);
    632        1.1   mycroft 	time(&gt->gt_ctime);
    633        1.1   mycroft 	gt->gt_grpmems	    = 0;
    634        1.1   mycroft 	gt->gt_scope	    = 0;
    635        1.1   mycroft 	gt->gt_prsent_timer = 0;
    636        1.1   mycroft 	gt->gt_grftsnt	    = 0;
    637        1.1   mycroft 	gt->gt_srctbl	    = NULL;
    638        1.1   mycroft 	gt->gt_pruntbl	    = NULL;
    639        1.1   mycroft 	gt->gt_route	    = r;
    640        1.3   mycroft #ifdef RSRR
    641        1.3   mycroft 	gt->gt_rsrr_cache   = NULL;
    642        1.3   mycroft #endif
    643        1.1   mycroft 
    644        1.1   mycroft 	if (r != NULL) {
    645        1.1   mycroft 	    /* obtain the multicast group membership list */
    646        1.1   mycroft 	    for (i = 0; i < numvifs; i++) {
    647        1.1   mycroft 		if (VIFM_ISSET(i, r->rt_children) &&
    648        1.1   mycroft 		    !(VIFM_ISSET(i, r->rt_leaves)))
    649        1.1   mycroft 		    VIFM_SET(i, gt->gt_grpmems);
    650        1.1   mycroft 
    651        1.1   mycroft 		if (VIFM_ISSET(i, r->rt_leaves) && grplst_mem(i, mcastgrp))
    652        1.1   mycroft 		    VIFM_SET(i, gt->gt_grpmems);
    653        1.1   mycroft 	    }
    654        1.1   mycroft 	    GET_SCOPE(gt);
    655        1.1   mycroft 	    if (VIFM_ISSET(r->rt_parent, gt->gt_scope))
    656        1.1   mycroft 		gt->gt_scope = -1;
    657        1.1   mycroft 	    gt->gt_grpmems &= ~gt->gt_scope;
    658        1.1   mycroft 	} else {
    659        1.1   mycroft 	    gt->gt_scope = -1;
    660        1.1   mycroft 	    gt->gt_grpmems = 0;
    661        1.1   mycroft 	}
    662        1.1   mycroft 
    663        1.1   mycroft 	/* update ttls */
    664        1.1   mycroft 	prun_add_ttls(gt);
    665        1.1   mycroft 
    666        1.1   mycroft 	gt->gt_next = *gtnp;
    667        1.1   mycroft 	*gtnp = gt;
    668        1.1   mycroft 	if (gt->gt_next)
    669        1.1   mycroft 	    gt->gt_next->gt_prev = gt;
    670        1.1   mycroft 	gt->gt_prev = prev_gt;
    671        1.1   mycroft 
    672        1.1   mycroft 	if (r) {
    673        1.1   mycroft 	    if (find_src_grp(r->rt_origin, r->rt_originmask, gt->gt_mcastgrp)) {
    674        1.1   mycroft 		struct gtable *g;
    675        1.1   mycroft 
    676        1.1   mycroft 		g = gtp ? gtp->gt_gnext : kernel_table;
    677       1.11       wiz 		logit(LOG_WARNING, 0, "Entry for (%s %s) (rt:%p) exists (rt:%p)",
    678       1.14       dsl 		    inet_fmts(r->rt_origin, r->rt_originmask),
    679       1.14       dsl 		    inet_fmt(g->gt_mcastgrp),
    680        1.1   mycroft 		    r, g->gt_route);
    681        1.1   mycroft 	    } else {
    682        1.1   mycroft 		if (gtp) {
    683        1.1   mycroft 		    gt->gt_gnext = gtp->gt_gnext;
    684        1.1   mycroft 		    gt->gt_gprev = gtp;
    685        1.1   mycroft 		    gtp->gt_gnext = gt;
    686        1.1   mycroft 		} else {
    687        1.1   mycroft 		    gt->gt_gnext = kernel_table;
    688        1.1   mycroft 		    gt->gt_gprev = NULL;
    689        1.1   mycroft 		    kernel_table = gt;
    690        1.1   mycroft 		}
    691        1.1   mycroft 		if (gt->gt_gnext)
    692        1.1   mycroft 		    gt->gt_gnext->gt_gprev = gt;
    693        1.1   mycroft 	    }
    694        1.1   mycroft 	} else {
    695        1.3   mycroft 	    gt->gt_gnext = gt->gt_gprev = NULL;
    696        1.1   mycroft 	}
    697        1.1   mycroft     }
    698        1.1   mycroft 
    699        1.1   mycroft     stnp = &gt->gt_srctbl;
    700        1.1   mycroft     while ((st = *stnp) != NULL) {
    701        1.1   mycroft 	if (ntohl(st->st_origin) >= ntohl(origin))
    702        1.1   mycroft 	    break;
    703        1.1   mycroft 	stnp = &st->st_next;
    704        1.1   mycroft     }
    705        1.1   mycroft 
    706        1.1   mycroft     if (st == NULL || st->st_origin != origin) {
    707        1.1   mycroft 	st = (struct stable *)malloc(sizeof(struct stable));
    708        1.1   mycroft 	if (st == NULL)
    709       1.11       wiz 	    logit(LOG_ERR, 0, "ran out of memory");
    710        1.1   mycroft 
    711        1.1   mycroft 	st->st_origin = origin;
    712        1.1   mycroft 	st->st_pktcnt = 0;
    713        1.1   mycroft 	st->st_next = *stnp;
    714        1.1   mycroft 	*stnp = st;
    715        1.1   mycroft     } else {
    716        1.3   mycroft #ifdef DEBUG_MFC
    717        1.3   mycroft 	md_log(MD_DUPE, origin, mcastgrp);
    718        1.3   mycroft #endif
    719       1.11       wiz 	logit(LOG_WARNING, 0, "kernel entry already exists for (%s %s)",
    720       1.14       dsl 		inet_fmt(origin),
    721       1.14       dsl 		inet_fmt(mcastgrp));
    722        1.3   mycroft 	/* XXX Doing this should cause no harm, and may ensure
    723        1.3   mycroft 	 * kernel<>mrouted synchronization */
    724        1.3   mycroft 	k_add_rg(origin, gt);
    725        1.1   mycroft 	return;
    726        1.1   mycroft     }
    727        1.1   mycroft 
    728        1.1   mycroft     kroutes++;
    729        1.1   mycroft     k_add_rg(origin, gt);
    730        1.1   mycroft 
    731       1.11       wiz     logit(LOG_DEBUG, 0, "add cache entry (%s %s) gm:%x, parent-vif:%d",
    732       1.14       dsl 	inet_fmt(origin),
    733       1.14       dsl 	inet_fmt(mcastgrp),
    734        1.1   mycroft 	gt->gt_grpmems, r ? r->rt_parent : -1);
    735        1.1   mycroft 
    736        1.1   mycroft     /* If there are no leaf vifs
    737        1.1   mycroft      * which have this group, then
    738        1.1   mycroft      * mark this src-grp as a prune candidate.
    739        1.1   mycroft      */
    740        1.1   mycroft     if (!gt->gt_prsent_timer && !gt->gt_grpmems && r && r->rt_gateway)
    741        1.1   mycroft 	send_prune(gt);
    742        1.1   mycroft }
    743        1.1   mycroft 
    744        1.1   mycroft /*
    745        1.1   mycroft  * An mrouter has gone down and come up on an interface
    746        1.1   mycroft  * Forward on that interface immediately
    747        1.1   mycroft  */
    748        1.1   mycroft void
    749        1.9       wiz reset_neighbor_state(vifi_t vifi, u_int32_t addr)
    750        1.1   mycroft {
    751        1.1   mycroft     struct rtentry *r;
    752        1.1   mycroft     struct gtable *g;
    753        1.3   mycroft     struct ptable *pt, **ptnp;
    754        1.3   mycroft     struct stable *st;
    755        1.1   mycroft 
    756        1.1   mycroft     for (g = kernel_table; g; g = g->gt_gnext) {
    757        1.1   mycroft 	r = g->gt_route;
    758        1.1   mycroft 
    759        1.1   mycroft 	/*
    760        1.1   mycroft 	 * If neighbor was the parent, remove the prune sent state
    761        1.3   mycroft 	 * and all of the source cache info so that prunes get
    762        1.3   mycroft 	 * regenerated.
    763        1.1   mycroft 	 */
    764        1.1   mycroft 	if (vifi == r->rt_parent) {
    765        1.1   mycroft 	    if (addr == r->rt_gateway) {
    766       1.11       wiz 		logit(LOG_DEBUG, 0, "reset_neighbor_state parent reset (%s %s)",
    767       1.14       dsl 		    inet_fmts(r->rt_origin, r->rt_originmask),
    768       1.14       dsl 		    inet_fmt(g->gt_mcastgrp));
    769        1.1   mycroft 
    770        1.3   mycroft 		g->gt_prsent_timer = 0;
    771        1.3   mycroft 		g->gt_grftsnt = 0;
    772        1.4     lukem 		while ((st = g->gt_srctbl) != NULL) {
    773        1.3   mycroft 		    g->gt_srctbl = st->st_next;
    774        1.3   mycroft 		    k_del_rg(st->st_origin, g);
    775        1.1   mycroft 		    kroutes--;
    776        1.3   mycroft 		    free(st);
    777        1.1   mycroft 		}
    778        1.1   mycroft 	    }
    779        1.1   mycroft 	} else {
    780        1.1   mycroft 	    /*
    781        1.1   mycroft 	     * Neighbor was not the parent, send grafts to join the groups
    782        1.1   mycroft 	     */
    783        1.1   mycroft 	    if (g->gt_prsent_timer) {
    784        1.1   mycroft 		g->gt_grftsnt = 1;
    785        1.1   mycroft 		send_graft(g);
    786        1.1   mycroft 		g->gt_prsent_timer = 0;
    787        1.1   mycroft 	    }
    788        1.1   mycroft 
    789        1.1   mycroft 	    /*
    790        1.1   mycroft 	     * Remove any prunes that this router has sent us.
    791        1.1   mycroft 	     */
    792        1.3   mycroft 	    ptnp = &g->gt_pruntbl;
    793        1.3   mycroft 	    while ((pt = *ptnp) != NULL) {
    794        1.1   mycroft 		if (pt->pt_vifi == vifi && pt->pt_router == addr) {
    795        1.3   mycroft 		    *ptnp = pt->pt_next;
    796        1.1   mycroft 		    free(pt);
    797        1.1   mycroft 		} else
    798        1.3   mycroft 		    ptnp = &pt->pt_next;
    799        1.1   mycroft 	    }
    800        1.1   mycroft 
    801        1.1   mycroft 	    /*
    802        1.1   mycroft 	     * And see if we want to forward again.
    803        1.1   mycroft 	     */
    804        1.1   mycroft 	    if (!VIFM_ISSET(vifi, g->gt_grpmems)) {
    805        1.1   mycroft 		if (VIFM_ISSET(vifi, r->rt_children) &&
    806        1.1   mycroft 		    !(VIFM_ISSET(vifi, r->rt_leaves)))
    807        1.1   mycroft 		    VIFM_SET(vifi, g->gt_grpmems);
    808        1.1   mycroft 
    809        1.1   mycroft 		if (VIFM_ISSET(vifi, r->rt_leaves) &&
    810        1.1   mycroft 		    grplst_mem(vifi, g->gt_mcastgrp))
    811        1.1   mycroft 		    VIFM_SET(vifi, g->gt_grpmems);
    812        1.1   mycroft 
    813        1.1   mycroft 		g->gt_grpmems &= ~g->gt_scope;
    814        1.1   mycroft 		prun_add_ttls(g);
    815        1.1   mycroft 
    816        1.1   mycroft 		/* Update kernel state */
    817        1.1   mycroft 		update_kernel(g);
    818        1.3   mycroft #ifdef RSRR
    819        1.3   mycroft 		/* Send route change notification to reservation protocol. */
    820        1.3   mycroft 		rsrr_cache_send(g,1);
    821        1.3   mycroft #endif /* RSRR */
    822        1.1   mycroft 
    823       1.11       wiz 		logit(LOG_DEBUG, 0, "reset member state (%s %s) gm:%x",
    824       1.14       dsl 		    inet_fmts(r->rt_origin, r->rt_originmask),
    825       1.14       dsl 		    inet_fmt(g->gt_mcastgrp), g->gt_grpmems);
    826        1.1   mycroft 	    }
    827        1.1   mycroft 	}
    828        1.1   mycroft     }
    829        1.1   mycroft }
    830        1.1   mycroft 
    831        1.1   mycroft /*
    832        1.1   mycroft  * Delete table entry from the kernel
    833        1.1   mycroft  * del_flag determines how many entries to delete
    834        1.1   mycroft  */
    835        1.1   mycroft void
    836        1.9       wiz del_table_entry(struct rtentry *r, u_int32_t mcastgrp, u_int del_flag)
    837        1.1   mycroft {
    838        1.1   mycroft     struct gtable *g, *prev_g;
    839        1.1   mycroft     struct stable *st, *prev_st;
    840        1.1   mycroft     struct ptable *pt, *prev_pt;
    841        1.1   mycroft 
    842        1.1   mycroft     if (del_flag == DEL_ALL_ROUTES) {
    843        1.1   mycroft 	g = r->rt_groups;
    844        1.1   mycroft 	while (g) {
    845       1.11       wiz 	    logit(LOG_DEBUG, 0, "del_table_entry deleting (%s %s)",
    846       1.14       dsl 		inet_fmts(r->rt_origin, r->rt_originmask),
    847       1.14       dsl 		inet_fmt(g->gt_mcastgrp));
    848        1.1   mycroft 	    st = g->gt_srctbl;
    849        1.1   mycroft 	    while (st) {
    850        1.1   mycroft 		if (k_del_rg(st->st_origin, g) < 0) {
    851       1.11       wiz 		    logit(LOG_WARNING, errno,
    852        1.1   mycroft 			"del_table_entry trying to delete (%s, %s)",
    853       1.14       dsl 			inet_fmt(st->st_origin),
    854       1.14       dsl 			inet_fmt(g->gt_mcastgrp));
    855        1.1   mycroft 		}
    856        1.1   mycroft 		kroutes--;
    857        1.1   mycroft 		prev_st = st;
    858        1.1   mycroft 		st = st->st_next;
    859        1.1   mycroft 		free(prev_st);
    860        1.1   mycroft 	    }
    861        1.1   mycroft 	    g->gt_srctbl = NULL;
    862        1.1   mycroft 
    863        1.1   mycroft 	    pt = g->gt_pruntbl;
    864        1.1   mycroft 	    while (pt) {
    865        1.3   mycroft 		prev_pt = pt;
    866        1.3   mycroft 		pt = pt->pt_next;
    867        1.3   mycroft 		free(prev_pt);
    868        1.1   mycroft 	    }
    869        1.1   mycroft 	    g->gt_pruntbl = NULL;
    870        1.1   mycroft 
    871        1.1   mycroft 	    if (g->gt_gnext)
    872        1.1   mycroft 		g->gt_gnext->gt_gprev = g->gt_gprev;
    873        1.1   mycroft 	    if (g->gt_gprev)
    874        1.1   mycroft 		g->gt_gprev->gt_gnext = g->gt_gnext;
    875        1.1   mycroft 	    else
    876        1.1   mycroft 		kernel_table = g->gt_gnext;
    877        1.1   mycroft 
    878        1.3   mycroft #ifdef RSRR
    879        1.3   mycroft 	    /* Send route change notification to reservation protocol. */
    880        1.3   mycroft 	    rsrr_cache_send(g,0);
    881        1.3   mycroft 	    rsrr_cache_clean(g);
    882        1.3   mycroft #endif /* RSRR */
    883        1.3   mycroft 	    prev_g = g;
    884        1.3   mycroft 	    g = g->gt_next;
    885        1.3   mycroft 	    free(prev_g);
    886        1.1   mycroft 	}
    887        1.1   mycroft 	r->rt_groups = NULL;
    888        1.1   mycroft     }
    889        1.1   mycroft 
    890        1.1   mycroft     /*
    891        1.1   mycroft      * Dummy routine - someday this may be needed, so it is just there
    892        1.1   mycroft      */
    893        1.1   mycroft     if (del_flag == DEL_RTE_GROUP) {
    894        1.1   mycroft 	prev_g = (struct gtable *)&r->rt_groups;
    895        1.1   mycroft 	for (g = r->rt_groups; g; g = g->gt_next) {
    896        1.1   mycroft 	    if (g->gt_mcastgrp == mcastgrp) {
    897       1.11       wiz 		logit(LOG_DEBUG, 0, "del_table_entry deleting (%s %s)",
    898       1.14       dsl 		    inet_fmts(r->rt_origin, r->rt_originmask),
    899       1.14       dsl 		    inet_fmt(g->gt_mcastgrp));
    900        1.1   mycroft 		st = g->gt_srctbl;
    901        1.1   mycroft 		while (st) {
    902        1.1   mycroft 		    if (k_del_rg(st->st_origin, g) < 0) {
    903       1.11       wiz 			logit(LOG_WARNING, errno,
    904        1.1   mycroft 			    "del_table_entry trying to delete (%s, %s)",
    905       1.14       dsl 			    inet_fmt(st->st_origin),
    906       1.14       dsl 			    inet_fmt(g->gt_mcastgrp));
    907        1.1   mycroft 		    }
    908        1.1   mycroft 		    kroutes--;
    909        1.3   mycroft 		    prev_st = st;
    910        1.3   mycroft 		    st = st->st_next;
    911        1.3   mycroft 		    free(prev_st);
    912        1.1   mycroft 		}
    913        1.1   mycroft 		g->gt_srctbl = NULL;
    914        1.1   mycroft 
    915        1.1   mycroft 		pt = g->gt_pruntbl;
    916        1.1   mycroft 		while (pt) {
    917        1.3   mycroft 		    prev_pt = pt;
    918        1.3   mycroft 		    pt = pt->pt_next;
    919        1.3   mycroft 		    free(prev_pt);
    920        1.1   mycroft 		}
    921        1.1   mycroft 		g->gt_pruntbl = NULL;
    922        1.1   mycroft 
    923        1.1   mycroft 		if (g->gt_gnext)
    924        1.1   mycroft 		    g->gt_gnext->gt_gprev = g->gt_gprev;
    925        1.1   mycroft 		if (g->gt_gprev)
    926        1.1   mycroft 		    g->gt_gprev->gt_gnext = g->gt_gnext;
    927        1.1   mycroft 		else
    928        1.1   mycroft 		    kernel_table = g->gt_gnext;
    929        1.1   mycroft 
    930        1.1   mycroft 		if (prev_g != (struct gtable *)&r->rt_groups)
    931        1.1   mycroft 		    g->gt_next->gt_prev = prev_g;
    932        1.1   mycroft 		else
    933        1.1   mycroft 		    g->gt_next->gt_prev = NULL;
    934        1.1   mycroft 		prev_g->gt_next = g->gt_next;
    935        1.1   mycroft 
    936        1.3   mycroft #ifdef RSRR
    937        1.3   mycroft 		/* Send route change notification to reservation protocol. */
    938        1.3   mycroft 		rsrr_cache_send(g,0);
    939        1.3   mycroft 		rsrr_cache_clean(g);
    940        1.3   mycroft #endif /* RSRR */
    941        1.1   mycroft 		free(g);
    942        1.1   mycroft 		g = prev_g;
    943        1.1   mycroft 	    } else {
    944        1.1   mycroft 		prev_g = g;
    945        1.1   mycroft 	    }
    946        1.1   mycroft 	}
    947        1.1   mycroft     }
    948        1.1   mycroft }
    949        1.1   mycroft 
    950        1.1   mycroft /*
    951        1.1   mycroft  * update kernel table entry when a route entry changes
    952        1.1   mycroft  */
    953        1.1   mycroft void
    954        1.9       wiz update_table_entry(struct rtentry *r)
    955        1.1   mycroft {
    956        1.1   mycroft     struct gtable *g;
    957        1.1   mycroft     struct ptable *pt, *prev_pt;
    958        1.3   mycroft     vifi_t i;
    959        1.1   mycroft 
    960        1.1   mycroft     for (g = r->rt_groups; g; g = g->gt_next) {
    961        1.1   mycroft 	pt = g->gt_pruntbl;
    962        1.1   mycroft 	while (pt) {
    963        1.1   mycroft 	    prev_pt = pt->pt_next;
    964        1.1   mycroft 	    free(pt);
    965        1.1   mycroft 	    pt = prev_pt;
    966        1.1   mycroft 	}
    967        1.1   mycroft 	g->gt_pruntbl = NULL;
    968        1.1   mycroft 
    969        1.1   mycroft 	g->gt_grpmems = 0;
    970        1.1   mycroft 
    971        1.1   mycroft 	/* obtain the multicast group membership list */
    972        1.1   mycroft 	for (i = 0; i < numvifs; i++) {
    973        1.1   mycroft 	    if (VIFM_ISSET(i, r->rt_children) &&
    974        1.1   mycroft 		!(VIFM_ISSET(i, r->rt_leaves)))
    975        1.1   mycroft 		VIFM_SET(i, g->gt_grpmems);
    976        1.1   mycroft 
    977        1.1   mycroft 	    if (VIFM_ISSET(i, r->rt_leaves) && grplst_mem(i, g->gt_mcastgrp))
    978        1.1   mycroft 		VIFM_SET(i, g->gt_grpmems);
    979        1.1   mycroft 	}
    980        1.1   mycroft 	if (VIFM_ISSET(r->rt_parent, g->gt_scope))
    981        1.1   mycroft 	    g->gt_scope = -1;
    982        1.1   mycroft 	g->gt_grpmems &= ~g->gt_scope;
    983        1.1   mycroft 
    984       1.11       wiz 	logit(LOG_DEBUG, 0, "updating cache entries (%s %s) gm:%x",
    985       1.14       dsl 	    inet_fmts(r->rt_origin, r->rt_originmask),
    986       1.14       dsl 	    inet_fmt(g->gt_mcastgrp),
    987        1.1   mycroft 	    g->gt_grpmems);
    988        1.1   mycroft 
    989        1.1   mycroft 	if (g->gt_grpmems && g->gt_prsent_timer) {
    990        1.1   mycroft 	    g->gt_grftsnt = 1;
    991        1.1   mycroft 	    send_graft(g);
    992        1.1   mycroft 	    g->gt_prsent_timer = 0;
    993        1.1   mycroft 	}
    994        1.1   mycroft 
    995        1.1   mycroft 	/* update ttls and add entry into kernel */
    996        1.1   mycroft 	prun_add_ttls(g);
    997        1.1   mycroft 	update_kernel(g);
    998        1.3   mycroft #ifdef RSRR
    999        1.3   mycroft 	/* Send route change notification to reservation protocol. */
   1000        1.3   mycroft 	rsrr_cache_send(g,1);
   1001        1.3   mycroft #endif /* RSRR */
   1002        1.1   mycroft 
   1003        1.1   mycroft 	/* Check if we want to prune this group */
   1004        1.1   mycroft 	if (!g->gt_prsent_timer && g->gt_grpmems == 0 && r->rt_gateway) {
   1005        1.1   mycroft 	    g->gt_timer = CACHE_LIFETIME(cache_lifetime);
   1006        1.1   mycroft 	    send_prune(g);
   1007        1.1   mycroft 	}
   1008        1.1   mycroft     }
   1009        1.1   mycroft }
   1010        1.1   mycroft 
   1011        1.1   mycroft /*
   1012        1.1   mycroft  * set the forwarding flag for all mcastgrps on this vifi
   1013        1.1   mycroft  */
   1014        1.1   mycroft void
   1015        1.9       wiz update_lclgrp(vifi_t vifi, u_int32_t mcastgrp)
   1016        1.1   mycroft {
   1017        1.1   mycroft     struct rtentry *r;
   1018        1.1   mycroft     struct gtable *g;
   1019        1.1   mycroft 
   1020       1.11       wiz     logit(LOG_DEBUG, 0, "group %s joined on vif %d",
   1021       1.14       dsl 	inet_fmt(mcastgrp), vifi);
   1022        1.1   mycroft 
   1023        1.1   mycroft     for (g = kernel_table; g; g = g->gt_gnext) {
   1024        1.1   mycroft 	if (ntohl(mcastgrp) < ntohl(g->gt_mcastgrp))
   1025        1.1   mycroft 	    break;
   1026        1.1   mycroft 
   1027        1.1   mycroft 	r = g->gt_route;
   1028        1.1   mycroft 	if (g->gt_mcastgrp == mcastgrp &&
   1029        1.1   mycroft 	    VIFM_ISSET(vifi, r->rt_children)) {
   1030        1.1   mycroft 
   1031        1.1   mycroft 	    VIFM_SET(vifi, g->gt_grpmems);
   1032        1.1   mycroft 	    g->gt_grpmems &= ~g->gt_scope;
   1033        1.1   mycroft 	    if (g->gt_grpmems == 0)
   1034        1.1   mycroft 		continue;
   1035        1.1   mycroft 
   1036        1.1   mycroft 	    prun_add_ttls(g);
   1037       1.11       wiz 	    logit(LOG_DEBUG, 0, "update lclgrp (%s %s) gm:%x",
   1038       1.14       dsl 		inet_fmts(r->rt_origin, r->rt_originmask),
   1039       1.14       dsl 		inet_fmt(g->gt_mcastgrp), g->gt_grpmems);
   1040        1.1   mycroft 
   1041        1.1   mycroft 	    update_kernel(g);
   1042        1.3   mycroft #ifdef RSRR
   1043        1.3   mycroft 	    /* Send route change notification to reservation protocol. */
   1044        1.3   mycroft 	    rsrr_cache_send(g,1);
   1045        1.3   mycroft #endif /* RSRR */
   1046        1.1   mycroft 	}
   1047        1.1   mycroft     }
   1048        1.1   mycroft }
   1049        1.1   mycroft 
   1050        1.1   mycroft /*
   1051        1.1   mycroft  * reset forwarding flag for all mcastgrps on this vifi
   1052        1.1   mycroft  */
   1053        1.1   mycroft void
   1054        1.9       wiz delete_lclgrp(vifi_t vifi, u_int32_t mcastgrp)
   1055        1.1   mycroft {
   1056        1.1   mycroft     struct rtentry *r;
   1057        1.1   mycroft     struct gtable *g;
   1058        1.1   mycroft 
   1059       1.11       wiz     logit(LOG_DEBUG, 0, "group %s left on vif %d",
   1060       1.14       dsl 	inet_fmt(mcastgrp), vifi);
   1061        1.1   mycroft 
   1062        1.1   mycroft     for (g = kernel_table; g; g = g->gt_gnext) {
   1063        1.1   mycroft 	if (ntohl(mcastgrp) < ntohl(g->gt_mcastgrp))
   1064        1.1   mycroft 	    break;
   1065        1.1   mycroft 
   1066        1.1   mycroft 	if (g->gt_mcastgrp == mcastgrp) {
   1067        1.1   mycroft 	    int stop_sending = 1;
   1068        1.1   mycroft 
   1069        1.1   mycroft 	    r = g->gt_route;
   1070        1.1   mycroft 	    /*
   1071        1.1   mycroft 	     * If this is not a leaf, then we have router neighbors on this
   1072        1.1   mycroft 	     * vif.  Only turn off forwarding if they have all pruned.
   1073        1.1   mycroft 	     */
   1074        1.1   mycroft 	    if (!VIFM_ISSET(vifi, r->rt_leaves)) {
   1075        1.1   mycroft 		struct listaddr *vr;
   1076        1.1   mycroft 
   1077        1.1   mycroft 		for (vr = uvifs[vifi].uv_neighbors; vr; vr = vr->al_next)
   1078        1.1   mycroft 		  if (find_prune_entry(vr->al_addr, g->gt_pruntbl) == NULL) {
   1079        1.1   mycroft 		      stop_sending = 0;
   1080        1.1   mycroft 		      break;
   1081        1.1   mycroft 		  }
   1082        1.1   mycroft 	    }
   1083        1.1   mycroft 
   1084        1.1   mycroft 	    if (stop_sending) {
   1085        1.1   mycroft 		VIFM_CLR(vifi, g->gt_grpmems);
   1086       1.11       wiz 		logit(LOG_DEBUG, 0, "delete lclgrp (%s %s) gm:%x",
   1087       1.14       dsl 		    inet_fmts(r->rt_origin, r->rt_originmask),
   1088       1.14       dsl 		    inet_fmt(g->gt_mcastgrp), g->gt_grpmems);
   1089        1.1   mycroft 
   1090        1.1   mycroft 		prun_add_ttls(g);
   1091        1.1   mycroft 		update_kernel(g);
   1092        1.3   mycroft #ifdef RSRR
   1093        1.3   mycroft 		/* Send route change notification to reservation protocol. */
   1094        1.3   mycroft 		rsrr_cache_send(g,1);
   1095        1.3   mycroft #endif /* RSRR */
   1096        1.1   mycroft 
   1097        1.1   mycroft 		/*
   1098        1.1   mycroft 		 * If there are no more members of this particular group,
   1099        1.1   mycroft 		 *  send prune upstream
   1100        1.1   mycroft 		 */
   1101        1.1   mycroft 		if (!g->gt_prsent_timer && g->gt_grpmems == 0 && r->rt_gateway)
   1102        1.1   mycroft 		    send_prune(g);
   1103        1.1   mycroft 	    }
   1104        1.1   mycroft 	}
   1105        1.1   mycroft     }
   1106        1.1   mycroft }
   1107        1.1   mycroft 
   1108        1.1   mycroft /*
   1109        1.1   mycroft  * Takes the prune message received and then strips it to
   1110        1.1   mycroft  * determine the (src, grp) pair to be pruned.
   1111        1.1   mycroft  *
   1112        1.1   mycroft  * Adds the router to the (src, grp) entry then.
   1113        1.1   mycroft  *
   1114        1.1   mycroft  * Determines if further packets have to be sent down that vif
   1115        1.1   mycroft  *
   1116        1.1   mycroft  * Determines if a corresponding prune message has to be generated
   1117        1.1   mycroft  */
   1118        1.1   mycroft void
   1119        1.9       wiz accept_prune(u_int32_t src, u_int32_t dst, char *p, int datalen)
   1120        1.1   mycroft {
   1121        1.1   mycroft     u_int32_t prun_src;
   1122        1.1   mycroft     u_int32_t prun_grp;
   1123        1.1   mycroft     u_int32_t prun_tmr;
   1124        1.1   mycroft     vifi_t vifi;
   1125        1.1   mycroft     int i;
   1126        1.1   mycroft     int stop_sending;
   1127        1.1   mycroft     struct rtentry *r;
   1128        1.1   mycroft     struct gtable *g;
   1129        1.1   mycroft     struct ptable *pt;
   1130        1.1   mycroft     struct listaddr *vr;
   1131        1.1   mycroft 
   1132        1.1   mycroft     /* Don't process any prunes if router is not pruning */
   1133        1.1   mycroft     if (pruning == 0)
   1134        1.1   mycroft 	return;
   1135        1.1   mycroft 
   1136        1.1   mycroft     if ((vifi = find_vif(src, dst)) == NO_VIF) {
   1137       1.11       wiz 	logit(LOG_INFO, 0,
   1138        1.1   mycroft     	    "ignoring prune report from non-neighbor %s",
   1139       1.14       dsl 	    inet_fmt(src));
   1140        1.1   mycroft 	return;
   1141        1.1   mycroft     }
   1142        1.1   mycroft 
   1143        1.1   mycroft     /* Check if enough data is present */
   1144        1.1   mycroft     if (datalen < 12)
   1145        1.1   mycroft 	{
   1146       1.11       wiz 	    logit(LOG_WARNING, 0,
   1147        1.1   mycroft 		"non-decipherable prune from %s",
   1148       1.14       dsl 		inet_fmt(src));
   1149        1.1   mycroft 	    return;
   1150        1.1   mycroft 	}
   1151        1.1   mycroft 
   1152        1.1   mycroft     for (i = 0; i< 4; i++)
   1153        1.1   mycroft 	((char *)&prun_src)[i] = *p++;
   1154        1.1   mycroft     for (i = 0; i< 4; i++)
   1155        1.1   mycroft 	((char *)&prun_grp)[i] = *p++;
   1156        1.1   mycroft     for (i = 0; i< 4; i++)
   1157        1.1   mycroft 	((char *)&prun_tmr)[i] = *p++;
   1158        1.3   mycroft     prun_tmr = ntohl(prun_tmr);
   1159        1.1   mycroft 
   1160       1.11       wiz     logit(LOG_DEBUG, 0, "%s on vif %d prunes (%s %s)/%d",
   1161       1.14       dsl 	inet_fmt(src), vifi,
   1162       1.14       dsl 	inet_fmt(prun_src), inet_fmt(prun_grp), prun_tmr);
   1163        1.1   mycroft 
   1164        1.1   mycroft     /*
   1165        1.1   mycroft      * Find the subnet for the prune
   1166        1.1   mycroft      */
   1167        1.1   mycroft     if (find_src_grp(prun_src, 0, prun_grp)) {
   1168        1.1   mycroft 	g = gtp ? gtp->gt_gnext : kernel_table;
   1169        1.1   mycroft     	r = g->gt_route;
   1170        1.1   mycroft 
   1171        1.1   mycroft 	if (!VIFM_ISSET(vifi, r->rt_children)) {
   1172       1.11       wiz 	    logit(LOG_WARNING, 0, "prune received from non-child %s for (%s %s)",
   1173       1.14       dsl 		inet_fmt(src), inet_fmt(prun_src),
   1174       1.14       dsl 		inet_fmt(prun_grp));
   1175        1.1   mycroft 	    return;
   1176        1.1   mycroft 	}
   1177        1.1   mycroft 	if (VIFM_ISSET(vifi, g->gt_scope)) {
   1178       1.11       wiz 	    logit(LOG_WARNING, 0, "prune received from %s on scoped grp (%s %s)",
   1179       1.14       dsl 		inet_fmt(src), inet_fmt(prun_src),
   1180       1.14       dsl 		inet_fmt(prun_grp));
   1181        1.1   mycroft 	    return;
   1182        1.1   mycroft 	}
   1183        1.1   mycroft 	if ((pt = find_prune_entry(src, g->gt_pruntbl)) != NULL) {
   1184        1.1   mycroft 	    /*
   1185        1.1   mycroft 	     * If it's about to expire, then it's only still around because
   1186        1.1   mycroft 	     * of timer granularity, so don't warn about it.
   1187        1.1   mycroft 	     */
   1188        1.1   mycroft 	    if (pt->pt_timer > 10) {
   1189       1.11       wiz 		logit(LOG_WARNING, 0, "%s %d from %s for (%s %s)/%d %s %d %s %x",
   1190        1.1   mycroft 		    "duplicate prune received on vif",
   1191       1.14       dsl 		    vifi, inet_fmt(src), inet_fmt(prun_src),
   1192       1.14       dsl 		    inet_fmt(prun_grp), prun_tmr,
   1193        1.1   mycroft 		    "old timer:", pt->pt_timer, "cur gm:", g->gt_grpmems);
   1194        1.1   mycroft 	    }
   1195        1.1   mycroft 	    pt->pt_timer = prun_tmr;
   1196        1.1   mycroft 	} else {
   1197        1.1   mycroft 	    /* allocate space for the prune structure */
   1198        1.1   mycroft 	    pt = (struct ptable *)(malloc(sizeof(struct ptable)));
   1199       1.17  christos 	    if (pt == NULL) {
   1200       1.11       wiz 	      logit(LOG_ERR, 0, "pt: ran out of memory");
   1201       1.17  christos 	      return;
   1202       1.17  christos 	    }
   1203        1.1   mycroft 
   1204        1.1   mycroft 	    pt->pt_vifi = vifi;
   1205        1.1   mycroft 	    pt->pt_router = src;
   1206        1.1   mycroft 	    pt->pt_timer = prun_tmr;
   1207        1.1   mycroft 
   1208        1.1   mycroft 	    pt->pt_next = g->gt_pruntbl;
   1209        1.1   mycroft 	    g->gt_pruntbl = pt;
   1210        1.1   mycroft 	}
   1211        1.1   mycroft 
   1212        1.1   mycroft 	/* Refresh the group's lifetime */
   1213        1.1   mycroft 	g->gt_timer = CACHE_LIFETIME(cache_lifetime);
   1214  1.17.28.1       jym 	if ((u_int32_t)g->gt_timer < prun_tmr)
   1215        1.1   mycroft 	    g->gt_timer = prun_tmr;
   1216        1.3   mycroft 
   1217        1.1   mycroft 	/*
   1218        1.1   mycroft 	 * check if any more packets need to be sent on the
   1219        1.1   mycroft 	 * vif which sent this message
   1220        1.1   mycroft 	 */
   1221        1.1   mycroft 	stop_sending = 1;
   1222        1.1   mycroft 	for (vr = uvifs[vifi].uv_neighbors; vr; vr = vr->al_next)
   1223        1.1   mycroft 	  if (find_prune_entry(vr->al_addr, g->gt_pruntbl) == NULL)  {
   1224        1.1   mycroft 	      stop_sending = 0;
   1225        1.1   mycroft 	      break;
   1226        1.1   mycroft 	  }
   1227        1.1   mycroft 
   1228        1.1   mycroft 	if (stop_sending && !grplst_mem(vifi, prun_grp)) {
   1229        1.1   mycroft 	    VIFM_CLR(vifi, g->gt_grpmems);
   1230       1.11       wiz 	    logit(LOG_DEBUG, 0, "prune (%s %s), stop sending on vif %d, gm:%x",
   1231       1.14       dsl 		inet_fmts(r->rt_origin, r->rt_originmask),
   1232       1.14       dsl 		inet_fmt(g->gt_mcastgrp), vifi, g->gt_grpmems);
   1233        1.1   mycroft 
   1234        1.1   mycroft 	    prun_add_ttls(g);
   1235        1.1   mycroft 	    update_kernel(g);
   1236        1.3   mycroft #ifdef RSRR
   1237        1.3   mycroft 	    /* Send route change notification to reservation protocol. */
   1238        1.3   mycroft 	    rsrr_cache_send(g,1);
   1239        1.3   mycroft #endif /* RSRR */
   1240        1.1   mycroft 	}
   1241        1.1   mycroft 
   1242        1.1   mycroft 	/*
   1243        1.1   mycroft 	 * check if all the child routers have expressed no interest
   1244        1.1   mycroft 	 * in this group and if this group does not exist in the
   1245        1.1   mycroft 	 * interface
   1246        1.1   mycroft 	 * Send a prune message then upstream
   1247        1.1   mycroft 	 */
   1248        1.1   mycroft 	if (!g->gt_prsent_timer && g->gt_grpmems == 0 && r->rt_gateway) {
   1249        1.1   mycroft 	    send_prune(g);
   1250        1.1   mycroft 	}
   1251        1.1   mycroft     } else {
   1252        1.1   mycroft 	/*
   1253        1.1   mycroft 	 * There is no kernel entry for this group.  Therefore, we can
   1254        1.1   mycroft 	 * simply ignore the prune, as we are not forwarding this traffic
   1255        1.1   mycroft 	 * downstream.
   1256        1.1   mycroft 	 */
   1257       1.11       wiz 	logit(LOG_DEBUG, 0, "%s (%s %s)/%d from %s",
   1258        1.1   mycroft 	    "prune message received with no kernel entry for",
   1259       1.14       dsl 	    inet_fmt(prun_src), inet_fmt(prun_grp),
   1260       1.14       dsl 	    prun_tmr, inet_fmt(src));
   1261        1.1   mycroft 	return;
   1262        1.1   mycroft     }
   1263        1.1   mycroft }
   1264        1.1   mycroft 
   1265        1.1   mycroft /*
   1266        1.1   mycroft  * Checks if this mcastgrp is present in the kernel table
   1267        1.1   mycroft  * If so and if a prune was sent, it sends a graft upwards
   1268        1.1   mycroft  */
   1269        1.1   mycroft void
   1270        1.9       wiz chkgrp_graft(vifi_t vifi, u_int32_t mcastgrp)
   1271        1.1   mycroft {
   1272        1.1   mycroft     struct rtentry *r;
   1273        1.1   mycroft     struct gtable *g;
   1274        1.1   mycroft 
   1275        1.1   mycroft     for (g = kernel_table; g; g = g->gt_gnext) {
   1276        1.1   mycroft 	if (ntohl(mcastgrp) < ntohl(g->gt_mcastgrp))
   1277        1.1   mycroft 	    break;
   1278        1.1   mycroft 
   1279        1.1   mycroft 	r = g->gt_route;
   1280        1.1   mycroft 	if (g->gt_mcastgrp == mcastgrp && VIFM_ISSET(vifi, r->rt_children))
   1281        1.1   mycroft 	    if (g->gt_prsent_timer) {
   1282        1.1   mycroft 		VIFM_SET(vifi, g->gt_grpmems);
   1283        1.1   mycroft 
   1284        1.1   mycroft 		/*
   1285        1.1   mycroft 		 * If the vif that was joined was a scoped vif,
   1286        1.1   mycroft 		 * ignore it ; don't graft back
   1287        1.1   mycroft 		 */
   1288        1.1   mycroft 		g->gt_grpmems &= ~g->gt_scope;
   1289        1.1   mycroft 		if (g->gt_grpmems == 0)
   1290        1.1   mycroft 		    continue;
   1291        1.1   mycroft 
   1292        1.1   mycroft 		/* set the flag for graft retransmission */
   1293        1.1   mycroft 		g->gt_grftsnt = 1;
   1294        1.1   mycroft 
   1295        1.1   mycroft 		/* send graft upwards */
   1296        1.1   mycroft 		send_graft(g);
   1297        1.1   mycroft 
   1298        1.1   mycroft 		/* reset the prune timer and update cache timer*/
   1299        1.1   mycroft 		g->gt_prsent_timer = 0;
   1300        1.1   mycroft 		g->gt_timer = max_prune_lifetime;
   1301        1.1   mycroft 
   1302       1.11       wiz 		logit(LOG_DEBUG, 0, "chkgrp graft (%s %s) gm:%x",
   1303       1.14       dsl 		    inet_fmts(r->rt_origin, r->rt_originmask),
   1304       1.14       dsl 		    inet_fmt(g->gt_mcastgrp), g->gt_grpmems);
   1305        1.1   mycroft 
   1306        1.1   mycroft 		prun_add_ttls(g);
   1307        1.1   mycroft 		update_kernel(g);
   1308        1.3   mycroft #ifdef RSRR
   1309        1.3   mycroft 		/* Send route change notification to reservation protocol. */
   1310        1.3   mycroft 		rsrr_cache_send(g,1);
   1311        1.3   mycroft #endif /* RSRR */
   1312        1.1   mycroft 	    }
   1313        1.1   mycroft     }
   1314        1.1   mycroft }
   1315        1.1   mycroft 
   1316        1.1   mycroft /* determine the multicast group and src
   1317        1.1   mycroft  *
   1318        1.1   mycroft  * if it does, then determine if a prune was sent
   1319        1.1   mycroft  * upstream.
   1320        1.1   mycroft  * if prune sent upstream, send graft upstream and send
   1321        1.1   mycroft  * ack downstream.
   1322        1.1   mycroft  *
   1323        1.1   mycroft  * if no prune sent upstream, change the forwarding bit
   1324        1.1   mycroft  * for this interface and send ack downstream.
   1325        1.1   mycroft  *
   1326        1.1   mycroft  * if no entry exists for this group send ack downstream.
   1327        1.1   mycroft  */
   1328        1.1   mycroft void
   1329        1.9       wiz accept_graft(u_int32_t src, u_int32_t dst, char *p, int datalen)
   1330        1.1   mycroft {
   1331        1.1   mycroft     vifi_t 	vifi;
   1332        1.1   mycroft     u_int32_t 	graft_src;
   1333        1.1   mycroft     u_int32_t	graft_grp;
   1334        1.1   mycroft     int 	i;
   1335        1.1   mycroft     struct rtentry *r;
   1336        1.1   mycroft     struct gtable *g;
   1337        1.1   mycroft     struct ptable *pt, **ptnp;
   1338        1.1   mycroft 
   1339        1.1   mycroft     if ((vifi = find_vif(src, dst)) == NO_VIF) {
   1340       1.11       wiz 	logit(LOG_INFO, 0,
   1341        1.1   mycroft     	    "ignoring graft from non-neighbor %s",
   1342       1.14       dsl 	    inet_fmt(src));
   1343        1.1   mycroft 	return;
   1344        1.1   mycroft     }
   1345        1.1   mycroft 
   1346        1.1   mycroft     if (datalen < 8) {
   1347       1.11       wiz 	logit(LOG_WARNING, 0,
   1348        1.1   mycroft 	    "received non-decipherable graft from %s",
   1349       1.14       dsl 	    inet_fmt(src));
   1350        1.1   mycroft 	return;
   1351        1.1   mycroft     }
   1352        1.1   mycroft 
   1353        1.1   mycroft     for (i = 0; i< 4; i++)
   1354        1.1   mycroft 	((char *)&graft_src)[i] = *p++;
   1355        1.1   mycroft     for (i = 0; i< 4; i++)
   1356        1.1   mycroft 	((char *)&graft_grp)[i] = *p++;
   1357        1.1   mycroft 
   1358       1.11       wiz     logit(LOG_DEBUG, 0, "%s on vif %d grafts (%s %s)",
   1359       1.14       dsl 	inet_fmt(src), vifi,
   1360       1.14       dsl 	inet_fmt(graft_src), inet_fmt(graft_grp));
   1361        1.1   mycroft 
   1362        1.1   mycroft     /*
   1363        1.1   mycroft      * Find the subnet for the graft
   1364        1.1   mycroft      */
   1365        1.1   mycroft     if (find_src_grp(graft_src, 0, graft_grp)) {
   1366        1.1   mycroft 	g = gtp ? gtp->gt_gnext : kernel_table;
   1367        1.1   mycroft 	r = g->gt_route;
   1368        1.1   mycroft 
   1369        1.1   mycroft 	if (VIFM_ISSET(vifi, g->gt_scope)) {
   1370       1.11       wiz 	    logit(LOG_WARNING, 0, "graft received from %s on scoped grp (%s %s)",
   1371       1.14       dsl 		inet_fmt(src), inet_fmt(graft_src),
   1372       1.14       dsl 		inet_fmt(graft_grp));
   1373        1.1   mycroft 	    return;
   1374        1.1   mycroft 	}
   1375        1.1   mycroft 
   1376        1.1   mycroft 	ptnp = &g->gt_pruntbl;
   1377        1.1   mycroft 	while ((pt = *ptnp) != NULL) {
   1378        1.1   mycroft 	    if ((pt->pt_vifi == vifi) && (pt->pt_router == src)) {
   1379        1.1   mycroft 		*ptnp = pt->pt_next;
   1380        1.1   mycroft 		free(pt);
   1381        1.1   mycroft 
   1382        1.1   mycroft 		VIFM_SET(vifi, g->gt_grpmems);
   1383       1.11       wiz 		logit(LOG_DEBUG, 0, "accept graft (%s %s) gm:%x",
   1384       1.14       dsl 		    inet_fmts(r->rt_origin, r->rt_originmask),
   1385       1.14       dsl 		    inet_fmt(g->gt_mcastgrp), g->gt_grpmems);
   1386        1.1   mycroft 
   1387        1.1   mycroft 		prun_add_ttls(g);
   1388        1.1   mycroft 		update_kernel(g);
   1389        1.3   mycroft #ifdef RSRR
   1390        1.3   mycroft 		/* Send route change notification to reservation protocol. */
   1391        1.3   mycroft 		rsrr_cache_send(g,1);
   1392        1.3   mycroft #endif /* RSRR */
   1393        1.1   mycroft 		break;
   1394        1.1   mycroft 	    } else {
   1395        1.1   mycroft 		ptnp = &pt->pt_next;
   1396        1.1   mycroft 	    }
   1397        1.1   mycroft 	}
   1398        1.1   mycroft 
   1399        1.1   mycroft 	/* send ack downstream */
   1400        1.1   mycroft 	send_graft_ack(dst, src, graft_src, graft_grp);
   1401        1.1   mycroft 	g->gt_timer = max_prune_lifetime;
   1402        1.1   mycroft 
   1403        1.1   mycroft 	if (g->gt_prsent_timer) {
   1404        1.1   mycroft 	    /* set the flag for graft retransmission */
   1405        1.1   mycroft 	    g->gt_grftsnt = 1;
   1406        1.1   mycroft 
   1407        1.1   mycroft 	    /* send graft upwards */
   1408        1.1   mycroft 	    send_graft(g);
   1409        1.1   mycroft 
   1410        1.1   mycroft 	    /* reset the prune sent timer */
   1411        1.1   mycroft 	    g->gt_prsent_timer = 0;
   1412        1.1   mycroft 	}
   1413        1.1   mycroft     } else {
   1414        1.1   mycroft 	/*
   1415        1.1   mycroft 	 * We have no state for the source and group in question.
   1416        1.1   mycroft 	 * We can simply acknowledge the graft, since we know
   1417        1.1   mycroft 	 * that we have no prune state, and grafts are requests
   1418        1.1   mycroft 	 * to remove prune state.
   1419        1.1   mycroft 	 */
   1420        1.1   mycroft 	send_graft_ack(dst, src, graft_src, graft_grp);
   1421       1.11       wiz 	logit(LOG_DEBUG, 0, "%s (%s %s) from %s",
   1422        1.1   mycroft 	    "graft received with no kernel entry for",
   1423       1.14       dsl 	    inet_fmt(graft_src), inet_fmt(graft_grp),
   1424       1.14       dsl 	    inet_fmt(src));
   1425        1.1   mycroft 	return;
   1426        1.1   mycroft     }
   1427        1.1   mycroft }
   1428        1.1   mycroft 
   1429        1.1   mycroft /*
   1430        1.1   mycroft  * find out which group is involved first of all
   1431        1.1   mycroft  * then determine if a graft was sent.
   1432        1.1   mycroft  * if no graft sent, ignore the message
   1433        1.1   mycroft  * if graft was sent and the ack is from the right
   1434        1.1   mycroft  * source, remove the graft timer so that we don't
   1435        1.1   mycroft  * have send a graft again
   1436        1.1   mycroft  */
   1437        1.1   mycroft void
   1438        1.9       wiz accept_g_ack(u_int32_t src, u_int32_t dst, char *p, int datalen)
   1439        1.1   mycroft {
   1440        1.1   mycroft     struct gtable *g;
   1441        1.1   mycroft     vifi_t 	vifi;
   1442        1.1   mycroft     u_int32_t 	grft_src;
   1443        1.1   mycroft     u_int32_t	grft_grp;
   1444        1.1   mycroft     int 	i;
   1445        1.1   mycroft 
   1446        1.1   mycroft     if ((vifi = find_vif(src, dst)) == NO_VIF) {
   1447       1.11       wiz 	logit(LOG_INFO, 0,
   1448        1.1   mycroft     	    "ignoring graft ack from non-neighbor %s",
   1449       1.14       dsl 	    inet_fmt(src));
   1450        1.1   mycroft 	return;
   1451        1.1   mycroft     }
   1452        1.1   mycroft 
   1453        1.1   mycroft     if (datalen < 0  || datalen > 8) {
   1454       1.11       wiz 	logit(LOG_WARNING, 0,
   1455        1.1   mycroft 	    "received non-decipherable graft ack from %s",
   1456       1.14       dsl 	    inet_fmt(src));
   1457        1.1   mycroft 	return;
   1458        1.1   mycroft     }
   1459        1.1   mycroft 
   1460        1.1   mycroft     for (i = 0; i< 4; i++)
   1461        1.1   mycroft 	((char *)&grft_src)[i] = *p++;
   1462        1.1   mycroft     for (i = 0; i< 4; i++)
   1463        1.1   mycroft 	((char *)&grft_grp)[i] = *p++;
   1464        1.1   mycroft 
   1465       1.11       wiz     logit(LOG_DEBUG, 0, "%s on vif %d acks graft (%s, %s)",
   1466       1.14       dsl 	inet_fmt(src), vifi,
   1467       1.14       dsl 	inet_fmt(grft_src), inet_fmt(grft_grp));
   1468        1.1   mycroft 
   1469        1.1   mycroft     /*
   1470        1.1   mycroft      * Find the subnet for the graft ack
   1471        1.1   mycroft      */
   1472        1.1   mycroft     if (find_src_grp(grft_src, 0, grft_grp)) {
   1473        1.1   mycroft 	g = gtp ? gtp->gt_gnext : kernel_table;
   1474        1.1   mycroft 	g->gt_grftsnt = 0;
   1475        1.1   mycroft     } else {
   1476       1.11       wiz 	logit(LOG_WARNING, 0, "%s (%s, %s) from %s",
   1477        1.1   mycroft 	    "rcvd graft ack with no kernel entry for",
   1478       1.14       dsl 	    inet_fmt(grft_src), inet_fmt(grft_grp),
   1479       1.14       dsl 	    inet_fmt(src));
   1480        1.1   mycroft 	return;
   1481        1.1   mycroft     }
   1482        1.1   mycroft }
   1483        1.1   mycroft 
   1484        1.1   mycroft 
   1485        1.1   mycroft /*
   1486        1.1   mycroft  * free all prune entries and kernel routes
   1487        1.1   mycroft  * normally, this should inform the kernel that all of its routes
   1488        1.1   mycroft  * are going away, but this is only called by restart(), which is
   1489        1.1   mycroft  * about to call MRT_DONE which does that anyway.
   1490        1.1   mycroft  */
   1491        1.1   mycroft void
   1492        1.9       wiz free_all_prunes(void)
   1493        1.1   mycroft {
   1494        1.9       wiz     struct rtentry *r;
   1495        1.9       wiz     struct gtable *g, *prev_g;
   1496        1.9       wiz     struct stable *s, *prev_s;
   1497        1.9       wiz     struct ptable *p, *prev_p;
   1498        1.1   mycroft 
   1499        1.1   mycroft     for (r = routing_table; r; r = r->rt_next) {
   1500        1.1   mycroft 	g = r->rt_groups;
   1501        1.1   mycroft 	while (g) {
   1502        1.1   mycroft 	    s = g->gt_srctbl;
   1503        1.1   mycroft 	    while (s) {
   1504        1.3   mycroft 		prev_s = s;
   1505        1.3   mycroft 		s = s->st_next;
   1506        1.3   mycroft 		free(prev_s);
   1507        1.1   mycroft 	    }
   1508        1.1   mycroft 
   1509        1.1   mycroft 	    p = g->gt_pruntbl;
   1510        1.1   mycroft 	    while (p) {
   1511        1.3   mycroft 		prev_p = p;
   1512        1.3   mycroft 		p = p->pt_next;
   1513        1.3   mycroft 		free(prev_p);
   1514        1.1   mycroft 	    }
   1515        1.1   mycroft 
   1516        1.3   mycroft 	    prev_g = g;
   1517        1.3   mycroft 	    g = g->gt_next;
   1518        1.3   mycroft 	    free(prev_g);
   1519        1.1   mycroft 	}
   1520        1.1   mycroft 	r->rt_groups = NULL;
   1521        1.1   mycroft     }
   1522        1.1   mycroft     kernel_table = NULL;
   1523        1.1   mycroft 
   1524        1.1   mycroft     g = kernel_no_route;
   1525        1.1   mycroft     while (g) {
   1526        1.1   mycroft 	if (g->gt_srctbl)
   1527        1.1   mycroft 	    free(g->gt_srctbl);
   1528        1.1   mycroft 
   1529        1.3   mycroft 	prev_g = g;
   1530        1.3   mycroft 	g = g->gt_next;
   1531        1.3   mycroft 	free(prev_g);
   1532        1.1   mycroft     }
   1533        1.1   mycroft     kernel_no_route = NULL;
   1534        1.1   mycroft }
   1535        1.1   mycroft 
   1536        1.1   mycroft /*
   1537        1.1   mycroft  * When a new route is created, search
   1538        1.1   mycroft  * a) The less-specific part of the routing table
   1539        1.1   mycroft  * b) The route-less kernel table
   1540        1.1   mycroft  * for sources that the new route might want to handle.
   1541        1.1   mycroft  *
   1542        1.1   mycroft  * "Inheriting" these sources might be cleanest, but simply deleting
   1543        1.1   mycroft  * them is easier, and letting the kernel re-request them.
   1544        1.1   mycroft  */
   1545        1.1   mycroft void
   1546        1.9       wiz steal_sources(struct rtentry *rt)
   1547        1.1   mycroft {
   1548        1.9       wiz     struct rtentry *rp;
   1549        1.9       wiz     struct gtable *gt, **gtnp;
   1550        1.9       wiz     struct stable *st, **stnp;
   1551        1.1   mycroft 
   1552        1.1   mycroft     for (rp = rt->rt_next; rp; rp = rp->rt_next) {
   1553        1.1   mycroft 	if ((rt->rt_origin & rp->rt_originmask) == rp->rt_origin) {
   1554       1.11       wiz 	    logit(LOG_DEBUG, 0, "Route for %s stealing sources from %s",
   1555       1.14       dsl 		inet_fmts(rt->rt_origin, rt->rt_originmask),
   1556       1.14       dsl 		inet_fmts(rp->rt_origin, rp->rt_originmask));
   1557        1.1   mycroft 	    for (gt = rp->rt_groups; gt; gt = gt->gt_next) {
   1558        1.1   mycroft 		stnp = &gt->gt_srctbl;
   1559        1.1   mycroft 		while ((st = *stnp) != NULL) {
   1560        1.1   mycroft 		    if ((st->st_origin & rt->rt_originmask) == rt->rt_origin) {
   1561       1.11       wiz 			logit(LOG_DEBUG, 0, "%s stealing (%s %s) from %s",
   1562       1.14       dsl 			    inet_fmts(rt->rt_origin, rt->rt_originmask),
   1563       1.14       dsl 			    inet_fmt(st->st_origin),
   1564       1.14       dsl 			    inet_fmt(gt->gt_mcastgrp),
   1565       1.14       dsl 			    inet_fmts(rp->rt_origin, rp->rt_originmask));
   1566        1.1   mycroft 			if (k_del_rg(st->st_origin, gt) < 0) {
   1567       1.11       wiz 			    logit(LOG_WARNING, errno, "%s (%s, %s)",
   1568        1.1   mycroft 				"steal_sources trying to delete",
   1569       1.14       dsl 				inet_fmt(st->st_origin),
   1570       1.14       dsl 				inet_fmt(gt->gt_mcastgrp));
   1571        1.1   mycroft 			}
   1572        1.1   mycroft 			*stnp = st->st_next;
   1573        1.1   mycroft 			kroutes--;
   1574        1.1   mycroft 			free(st);
   1575        1.1   mycroft 		    } else {
   1576        1.1   mycroft 			stnp = &st->st_next;
   1577        1.1   mycroft 		    }
   1578        1.1   mycroft 		}
   1579        1.1   mycroft 	    }
   1580        1.1   mycroft 	}
   1581        1.1   mycroft     }
   1582        1.1   mycroft 
   1583        1.1   mycroft     gtnp = &kernel_no_route;
   1584        1.1   mycroft     while ((gt = *gtnp) != NULL) {
   1585        1.1   mycroft 	if (gt->gt_srctbl && ((gt->gt_srctbl->st_origin & rt->rt_originmask)
   1586        1.1   mycroft 				    == rt->rt_origin)) {
   1587       1.11       wiz 	    logit(LOG_DEBUG, 0, "%s stealing (%s %s) from %s",
   1588       1.14       dsl 		inet_fmts(rt->rt_origin, rt->rt_originmask),
   1589       1.14       dsl 		inet_fmt(gt->gt_srctbl->st_origin),
   1590       1.14       dsl 		inet_fmt(gt->gt_mcastgrp),
   1591        1.1   mycroft 		"no_route table");
   1592        1.1   mycroft 	    if (k_del_rg(gt->gt_srctbl->st_origin, gt) < 0) {
   1593       1.11       wiz 		logit(LOG_WARNING, errno, "%s (%s %s)",
   1594        1.1   mycroft 		    "steal_sources trying to delete",
   1595       1.14       dsl 		    inet_fmt(gt->gt_srctbl->st_origin),
   1596       1.14       dsl 		    inet_fmt(gt->gt_mcastgrp));
   1597        1.1   mycroft 	    }
   1598        1.1   mycroft 	    kroutes--;
   1599        1.1   mycroft 	    free(gt->gt_srctbl);
   1600        1.1   mycroft 	    *gtnp = gt->gt_next;
   1601        1.1   mycroft 	    if (gt->gt_next)
   1602        1.1   mycroft 		gt->gt_next->gt_prev = gt->gt_prev;
   1603        1.1   mycroft 	    free(gt);
   1604        1.1   mycroft 	} else {
   1605        1.1   mycroft 	    gtnp = &gt->gt_next;
   1606        1.1   mycroft 	}
   1607        1.1   mycroft     }
   1608        1.1   mycroft }
   1609        1.1   mycroft 
   1610        1.1   mycroft /*
   1611        1.1   mycroft  * Advance the timers on all the cache entries.
   1612        1.1   mycroft  * If there are any entries whose timers have expired,
   1613        1.1   mycroft  * remove these entries from the kernel cache.
   1614        1.1   mycroft  */
   1615        1.1   mycroft void
   1616        1.9       wiz age_table_entry(void)
   1617        1.1   mycroft {
   1618        1.1   mycroft     struct rtentry *r;
   1619        1.1   mycroft     struct gtable *gt, **gtnptr;
   1620        1.1   mycroft     struct stable *st, **stnp;
   1621        1.1   mycroft     struct ptable *pt, **ptnp;
   1622        1.1   mycroft     struct sioc_sg_req sg_req;
   1623        1.1   mycroft 
   1624       1.11       wiz     logit(LOG_DEBUG, 0, "ageing entries");
   1625        1.1   mycroft 
   1626        1.1   mycroft     gtnptr = &kernel_table;
   1627        1.1   mycroft     while ((gt = *gtnptr) != NULL) {
   1628        1.1   mycroft 	r = gt->gt_route;
   1629        1.1   mycroft 
   1630        1.1   mycroft 	/* advance the timer for the kernel entry */
   1631        1.1   mycroft 	gt->gt_timer -= ROUTE_MAX_REPORT_DELAY;
   1632        1.1   mycroft 
   1633        1.1   mycroft 	/* decrement prune timer if need be */
   1634        1.1   mycroft 	if (gt->gt_prsent_timer > 0) {
   1635        1.1   mycroft 	    gt->gt_prsent_timer -= ROUTE_MAX_REPORT_DELAY;
   1636        1.1   mycroft 	    if (gt->gt_prsent_timer <= 0) {
   1637       1.11       wiz 		logit(LOG_DEBUG, 0, "upstream prune tmo (%s %s)",
   1638       1.14       dsl 		    inet_fmts(r->rt_origin, r->rt_originmask),
   1639       1.14       dsl 		    inet_fmt(gt->gt_mcastgrp));
   1640        1.1   mycroft 		gt->gt_prsent_timer = -1;
   1641        1.1   mycroft 	    }
   1642        1.1   mycroft 	}
   1643        1.1   mycroft 
   1644        1.1   mycroft 	/* retransmit graft if graft sent flag is still set */
   1645        1.1   mycroft 	if (gt->gt_grftsnt) {
   1646        1.9       wiz 	    int y;
   1647        1.1   mycroft 	    CHK_GS(gt->gt_grftsnt++, y);
   1648        1.1   mycroft 	    if (y)
   1649        1.1   mycroft 		send_graft(gt);
   1650        1.1   mycroft 	}
   1651        1.1   mycroft 
   1652        1.1   mycroft 	/*
   1653        1.1   mycroft 	 * Age prunes
   1654        1.1   mycroft 	 *
   1655        1.1   mycroft 	 * If a prune expires, forward again on that vif.
   1656        1.1   mycroft 	 */
   1657        1.1   mycroft 	ptnp = &gt->gt_pruntbl;
   1658        1.1   mycroft 	while ((pt = *ptnp) != NULL) {
   1659        1.1   mycroft 	    if ((pt->pt_timer -= ROUTE_MAX_REPORT_DELAY) <= 0) {
   1660       1.11       wiz 		logit(LOG_DEBUG, 0, "expire prune (%s %s) from %s on vif %d",
   1661       1.14       dsl 		    inet_fmts(r->rt_origin, r->rt_originmask),
   1662       1.14       dsl 		    inet_fmt(gt->gt_mcastgrp),
   1663       1.14       dsl 		    inet_fmt(pt->pt_router),
   1664        1.1   mycroft 		    pt->pt_vifi);
   1665        1.1   mycroft 
   1666        1.3   mycroft 		expire_prune(pt->pt_vifi, gt);
   1667        1.1   mycroft 
   1668        1.1   mycroft 		/* remove the router's prune entry and await new one */
   1669        1.1   mycroft 		*ptnp = pt->pt_next;
   1670        1.1   mycroft 		free(pt);
   1671        1.1   mycroft 	    } else {
   1672        1.1   mycroft 		ptnp = &pt->pt_next;
   1673        1.1   mycroft 	    }
   1674        1.1   mycroft 	}
   1675        1.1   mycroft 
   1676        1.1   mycroft 	/*
   1677        1.3   mycroft 	 * If the cache entry has expired, delete source table entries for
   1678        1.3   mycroft 	 * silent sources.  If there are no source entries left, and there
   1679        1.3   mycroft 	 * are no downstream prunes, then the entry is deleted.
   1680        1.3   mycroft 	 * Otherwise, the cache entry's timer is refreshed.
   1681        1.1   mycroft 	 */
   1682        1.1   mycroft 	if (gt->gt_timer <= 0) {
   1683        1.3   mycroft 	    /* Check for traffic before deleting source entries */
   1684        1.3   mycroft 	    sg_req.grp.s_addr = gt->gt_mcastgrp;
   1685        1.3   mycroft 	    stnp = &gt->gt_srctbl;
   1686        1.3   mycroft 	    while ((st = *stnp) != NULL) {
   1687        1.3   mycroft 		sg_req.src.s_addr = st->st_origin;
   1688        1.6       hwr 		if (ioctl(igmp_socket, SIOCGETSGCNT, (char *)&sg_req) < 0) {
   1689       1.11       wiz 		    logit(LOG_WARNING, errno, "%s (%s %s)",
   1690        1.3   mycroft 			"age_table_entry: SIOCGETSGCNT failing for",
   1691       1.14       dsl 			inet_fmt(st->st_origin),
   1692       1.14       dsl 			inet_fmt(gt->gt_mcastgrp));
   1693        1.3   mycroft 		    /* Make sure it gets deleted below */
   1694        1.3   mycroft 		    sg_req.pktcnt = st->st_pktcnt;
   1695        1.3   mycroft 		}
   1696        1.3   mycroft 		if (sg_req.pktcnt == st->st_pktcnt) {
   1697        1.3   mycroft 		    *stnp = st->st_next;
   1698       1.11       wiz 		    logit(LOG_DEBUG, 0, "age_table_entry deleting (%s %s)",
   1699       1.14       dsl 			inet_fmt(st->st_origin),
   1700       1.14       dsl 			inet_fmt(gt->gt_mcastgrp));
   1701        1.3   mycroft 		    if (k_del_rg(st->st_origin, gt) < 0) {
   1702       1.11       wiz 			logit(LOG_WARNING, errno,
   1703        1.3   mycroft 			    "age_table_entry trying to delete (%s %s)",
   1704       1.14       dsl 			    inet_fmt(st->st_origin),
   1705       1.14       dsl 			    inet_fmt(gt->gt_mcastgrp));
   1706        1.1   mycroft 		    }
   1707        1.3   mycroft 		    kroutes--;
   1708        1.3   mycroft 		    free(st);
   1709        1.3   mycroft 		} else {
   1710        1.3   mycroft 		    st->st_pktcnt = sg_req.pktcnt;
   1711        1.3   mycroft 		    stnp = &st->st_next;
   1712        1.1   mycroft 		}
   1713        1.3   mycroft 	    }
   1714        1.1   mycroft 
   1715        1.3   mycroft 	    /*
   1716        1.3   mycroft 	     * Retain the group entry if we have downstream prunes or if
   1717        1.3   mycroft 	     * there is at least one source in the list that still has
   1718        1.3   mycroft 	     * traffic, or if our upstream prune timer is running.
   1719        1.3   mycroft 	     */
   1720        1.3   mycroft 	    if (gt->gt_pruntbl != NULL || gt->gt_srctbl != NULL ||
   1721        1.3   mycroft 		gt->gt_prsent_timer > 0) {
   1722        1.3   mycroft 		gt->gt_timer = CACHE_LIFETIME(cache_lifetime);
   1723        1.5      ross 		if (gt->gt_prsent_timer == -1) {
   1724        1.3   mycroft 		    if (gt->gt_grpmems == 0)
   1725        1.3   mycroft 			send_prune(gt);
   1726        1.3   mycroft 		    else
   1727        1.3   mycroft 			gt->gt_prsent_timer = 0;
   1728        1.5      ross 		}
   1729        1.3   mycroft 		gtnptr = &gt->gt_gnext;
   1730        1.3   mycroft 		continue;
   1731        1.1   mycroft 	    }
   1732        1.1   mycroft 
   1733       1.11       wiz 	    logit(LOG_DEBUG, 0, "timeout cache entry (%s, %s)",
   1734       1.14       dsl 		inet_fmts(r->rt_origin, r->rt_originmask),
   1735       1.14       dsl 		inet_fmt(gt->gt_mcastgrp));
   1736        1.1   mycroft 
   1737        1.1   mycroft 	    if (gt->gt_prev)
   1738        1.1   mycroft 		gt->gt_prev->gt_next = gt->gt_next;
   1739        1.1   mycroft 	    else
   1740        1.1   mycroft 		gt->gt_route->rt_groups = gt->gt_next;
   1741        1.1   mycroft 	    if (gt->gt_next)
   1742        1.1   mycroft 		gt->gt_next->gt_prev = gt->gt_prev;
   1743        1.1   mycroft 
   1744        1.1   mycroft 	    if (gt->gt_gprev) {
   1745        1.1   mycroft 		gt->gt_gprev->gt_gnext = gt->gt_gnext;
   1746        1.1   mycroft 		gtnptr = &gt->gt_gprev->gt_gnext;
   1747        1.1   mycroft 	    } else {
   1748        1.1   mycroft 		kernel_table = gt->gt_gnext;
   1749        1.1   mycroft 		gtnptr = &kernel_table;
   1750        1.1   mycroft 	    }
   1751        1.1   mycroft 	    if (gt->gt_gnext)
   1752        1.1   mycroft 		gt->gt_gnext->gt_gprev = gt->gt_gprev;
   1753        1.1   mycroft 
   1754        1.3   mycroft #ifdef RSRR
   1755        1.3   mycroft 	    /* Send route change notification to reservation protocol. */
   1756        1.3   mycroft 	    rsrr_cache_send(gt,0);
   1757        1.3   mycroft 	    rsrr_cache_clean(gt);
   1758        1.3   mycroft #endif /* RSRR */
   1759        1.1   mycroft 	    free((char *)gt);
   1760        1.1   mycroft 	} else {
   1761        1.5      ross 	    if (gt->gt_prsent_timer == -1) {
   1762        1.3   mycroft 		if (gt->gt_grpmems == 0)
   1763        1.3   mycroft 		    send_prune(gt);
   1764        1.3   mycroft 		else
   1765        1.3   mycroft 		    gt->gt_prsent_timer = 0;
   1766        1.5      ross 	    }
   1767        1.1   mycroft 	    gtnptr = &gt->gt_gnext;
   1768        1.1   mycroft 	}
   1769        1.1   mycroft     }
   1770        1.1   mycroft 
   1771        1.1   mycroft     /*
   1772        1.1   mycroft      * When traversing the no_route table, the decision is much easier.
   1773        1.1   mycroft      * Just delete it if it has timed out.
   1774        1.1   mycroft      */
   1775        1.1   mycroft     gtnptr = &kernel_no_route;
   1776        1.1   mycroft     while ((gt = *gtnptr) != NULL) {
   1777        1.1   mycroft 	/* advance the timer for the kernel entry */
   1778        1.1   mycroft 	gt->gt_timer -= ROUTE_MAX_REPORT_DELAY;
   1779        1.1   mycroft 
   1780        1.1   mycroft 	if (gt->gt_timer < 0) {
   1781        1.1   mycroft 	    if (gt->gt_srctbl) {
   1782        1.1   mycroft 		if (k_del_rg(gt->gt_srctbl->st_origin, gt) < 0) {
   1783       1.11       wiz 		    logit(LOG_WARNING, errno, "%s (%s %s)",
   1784        1.1   mycroft 			"age_table_entry trying to delete no-route",
   1785       1.14       dsl 			inet_fmt(gt->gt_srctbl->st_origin),
   1786       1.14       dsl 			inet_fmt(gt->gt_mcastgrp));
   1787        1.1   mycroft 		}
   1788        1.1   mycroft 		free(gt->gt_srctbl);
   1789        1.1   mycroft 	    }
   1790        1.1   mycroft 	    *gtnptr = gt->gt_next;
   1791        1.1   mycroft 	    if (gt->gt_next)
   1792        1.1   mycroft 		gt->gt_next->gt_prev = gt->gt_prev;
   1793        1.1   mycroft 
   1794        1.1   mycroft 	    free((char *)gt);
   1795        1.1   mycroft 	} else {
   1796        1.1   mycroft 	    gtnptr = &gt->gt_next;
   1797        1.1   mycroft 	}
   1798        1.1   mycroft     }
   1799        1.1   mycroft }
   1800        1.1   mycroft 
   1801        1.3   mycroft /*
   1802        1.3   mycroft  * Modify the kernel to forward packets when one or multiple prunes that
   1803        1.3   mycroft  * were received on the vif given by vifi, for the group given by gt,
   1804        1.3   mycroft  * have expired.
   1805        1.3   mycroft  */
   1806        1.3   mycroft static void
   1807        1.9       wiz expire_prune(vifi_t vifi, struct gtable *gt)
   1808        1.3   mycroft {
   1809        1.3   mycroft     /*
   1810        1.3   mycroft      * No need to send a graft, any prunes that we sent
   1811        1.3   mycroft      * will expire before any prunes that we have received.
   1812        1.3   mycroft      */
   1813        1.3   mycroft     if (gt->gt_prsent_timer > 0) {
   1814       1.11       wiz         logit(LOG_DEBUG, 0, "prune expired with %d left on %s",
   1815        1.3   mycroft 		gt->gt_prsent_timer, "prsent_timer");
   1816        1.3   mycroft         gt->gt_prsent_timer = 0;
   1817        1.3   mycroft     }
   1818        1.3   mycroft 
   1819        1.3   mycroft     /* modify the kernel entry to forward packets */
   1820        1.3   mycroft     if (!VIFM_ISSET(vifi, gt->gt_grpmems)) {
   1821        1.3   mycroft         struct rtentry *rt = gt->gt_route;
   1822        1.3   mycroft         VIFM_SET(vifi, gt->gt_grpmems);
   1823       1.11       wiz         logit(LOG_DEBUG, 0, "forw again (%s %s) gm:%x vif:%d",
   1824       1.14       dsl 	inet_fmts(rt->rt_origin, rt->rt_originmask),
   1825       1.14       dsl 	inet_fmt(gt->gt_mcastgrp), gt->gt_grpmems, vifi);
   1826        1.3   mycroft 
   1827        1.3   mycroft         prun_add_ttls(gt);
   1828        1.3   mycroft         update_kernel(gt);
   1829        1.3   mycroft #ifdef RSRR
   1830        1.3   mycroft         /* Send route change notification to reservation protocol. */
   1831        1.3   mycroft         rsrr_cache_send(gt,1);
   1832        1.3   mycroft #endif /* RSRR */
   1833        1.3   mycroft     }
   1834        1.3   mycroft }
   1835        1.3   mycroft 
   1836        1.3   mycroft 
   1837  1.17.28.1       jym static const char *
   1838        1.9       wiz scaletime(u_long t)
   1839        1.1   mycroft {
   1840        1.1   mycroft     static char buf1[5];
   1841        1.1   mycroft     static char buf2[5];
   1842        1.1   mycroft     static char *buf=buf1;
   1843        1.1   mycroft     char s;
   1844        1.1   mycroft     char *p;
   1845        1.1   mycroft 
   1846        1.1   mycroft     p = buf;
   1847        1.1   mycroft     if (buf == buf1)
   1848        1.1   mycroft 	buf = buf2;
   1849        1.1   mycroft     else
   1850        1.1   mycroft 	buf = buf1;
   1851        1.1   mycroft 
   1852        1.1   mycroft     if (t < 120) {
   1853        1.1   mycroft 	s = 's';
   1854        1.1   mycroft     } else if (t < 3600) {
   1855        1.1   mycroft 	t /= 60;
   1856        1.1   mycroft 	s = 'm';
   1857        1.1   mycroft     } else if (t < 86400) {
   1858        1.1   mycroft 	t /= 3600;
   1859        1.1   mycroft 	s = 'h';
   1860        1.1   mycroft     } else if (t < 864000) {
   1861        1.1   mycroft 	t /= 86400;
   1862        1.1   mycroft 	s = 'd';
   1863        1.1   mycroft     } else {
   1864        1.1   mycroft 	t /= 604800;
   1865        1.1   mycroft 	s = 'w';
   1866        1.1   mycroft     }
   1867        1.1   mycroft     if (t > 999)
   1868        1.1   mycroft 	return "*** ";
   1869        1.1   mycroft 
   1870       1.13    itojun     snprintf(p, 5, "%3d%c", (int)t, s);
   1871        1.1   mycroft 
   1872        1.1   mycroft     return p;
   1873        1.1   mycroft }
   1874        1.1   mycroft 
   1875        1.1   mycroft /*
   1876        1.1   mycroft  * Print the contents of the cache table on file 'fp2'.
   1877        1.1   mycroft  */
   1878        1.1   mycroft void
   1879        1.9       wiz dump_cache(FILE *fp2)
   1880        1.1   mycroft {
   1881        1.9       wiz     struct rtentry *r;
   1882        1.9       wiz     struct gtable *gt;
   1883        1.9       wiz     struct stable *st;
   1884        1.9       wiz     vifi_t i;
   1885        1.9       wiz     time_t thyme = time(0);
   1886        1.1   mycroft 
   1887        1.1   mycroft     fprintf(fp2,
   1888        1.1   mycroft 	    "Multicast Routing Cache Table (%d entries)\n%s", kroutes,
   1889        1.1   mycroft     " Origin             Mcast-group     CTmr  Age Ptmr IVif Forwvifs\n");
   1890        1.1   mycroft 
   1891        1.1   mycroft     for (gt = kernel_no_route; gt; gt = gt->gt_next) {
   1892        1.1   mycroft 	if (gt->gt_srctbl) {
   1893        1.1   mycroft 	    fprintf(fp2, " %-18s %-15s %-4s %-4s    - -1\n",
   1894       1.14       dsl 		inet_fmts(gt->gt_srctbl->st_origin, 0xffffffff),
   1895       1.14       dsl 		inet_fmt(gt->gt_mcastgrp), scaletime(gt->gt_timer),
   1896        1.1   mycroft 		scaletime(thyme - gt->gt_ctime));
   1897       1.14       dsl 	    fprintf(fp2, ">%s\n", inet_fmt(gt->gt_srctbl->st_origin));
   1898        1.1   mycroft 	}
   1899        1.1   mycroft     }
   1900        1.1   mycroft 
   1901        1.1   mycroft     for (gt = kernel_table; gt; gt = gt->gt_gnext) {
   1902        1.1   mycroft 	r = gt->gt_route;
   1903        1.1   mycroft 	fprintf(fp2, " %-18s %-15s",
   1904       1.14       dsl 	    inet_fmts(r->rt_origin, r->rt_originmask),
   1905       1.14       dsl 	    inet_fmt(gt->gt_mcastgrp));
   1906        1.1   mycroft 
   1907        1.1   mycroft 	fprintf(fp2, " %-4s", scaletime(gt->gt_timer));
   1908        1.1   mycroft 
   1909        1.1   mycroft 	fprintf(fp2, " %-4s %-4s ", scaletime(thyme - gt->gt_ctime),
   1910        1.1   mycroft 			gt->gt_prsent_timer ? scaletime(gt->gt_prsent_timer) :
   1911        1.1   mycroft 					      "   -");
   1912        1.1   mycroft 
   1913        1.1   mycroft 	fprintf(fp2, "%2u%c%c ", r->rt_parent,
   1914        1.1   mycroft 	    gt->gt_prsent_timer ? 'P' : ' ',
   1915        1.1   mycroft 	    VIFM_ISSET(r->rt_parent, gt->gt_scope) ? 'B' : ' ');
   1916        1.1   mycroft 
   1917        1.1   mycroft 	for (i = 0; i < numvifs; ++i) {
   1918        1.1   mycroft 	    if (VIFM_ISSET(i, gt->gt_grpmems))
   1919        1.1   mycroft 		fprintf(fp2, " %u ", i);
   1920        1.1   mycroft 	    else if (VIFM_ISSET(i, r->rt_children) &&
   1921        1.1   mycroft 		     !VIFM_ISSET(i, r->rt_leaves))
   1922        1.1   mycroft 		fprintf(fp2, " %u%c", i,
   1923        1.1   mycroft 			VIFM_ISSET(i, gt->gt_scope) ? 'b' : 'p');
   1924        1.1   mycroft 	}
   1925        1.1   mycroft 	fprintf(fp2, "\n");
   1926        1.1   mycroft 	for (st = gt->gt_srctbl; st; st = st->st_next) {
   1927       1.14       dsl 	    fprintf(fp2, ">%s\n", inet_fmt(st->st_origin));
   1928        1.1   mycroft 	}
   1929        1.1   mycroft #ifdef DEBUG_PRUNES
   1930        1.1   mycroft 	for (pt = gt->gt_pruntbl; pt; pt = pt->pt_next) {
   1931       1.14       dsl 	    fprintf(fp2, "<r:%s v:%d t:%d\n", inet_fmt(pt->pt_router),
   1932        1.1   mycroft 		pt->pt_vifi, pt->pt_timer);
   1933        1.1   mycroft 	}
   1934        1.1   mycroft #endif
   1935        1.1   mycroft     }
   1936        1.1   mycroft }
   1937        1.1   mycroft 
   1938        1.1   mycroft /*
   1939        1.1   mycroft  * Traceroute function which returns traceroute replies to the requesting
   1940        1.1   mycroft  * router. Also forwards the request to downstream routers.
   1941        1.9       wiz  *
   1942        1.9       wiz  * no: promoted u_char
   1943        1.1   mycroft  */
   1944        1.1   mycroft void
   1945        1.9       wiz accept_mtrace(u_int32_t src, u_int32_t dst, u_int32_t group, char *data,
   1946        1.9       wiz 	      u_int no, int datalen)
   1947        1.1   mycroft {
   1948        1.1   mycroft     u_char type;
   1949        1.1   mycroft     struct rtentry *rt;
   1950        1.1   mycroft     struct gtable *gt;
   1951        1.1   mycroft     struct tr_query *qry;
   1952        1.1   mycroft     struct tr_resp  *resp;
   1953        1.1   mycroft     int vifi;
   1954        1.1   mycroft     char *p;
   1955        1.1   mycroft     int rcount;
   1956        1.1   mycroft     int errcode = TR_NO_ERR;
   1957        1.1   mycroft     int resptype;
   1958        1.1   mycroft     struct timeval tp;
   1959        1.1   mycroft     struct sioc_vif_req v_req;
   1960        1.1   mycroft     struct sioc_sg_req sg_req;
   1961        1.1   mycroft 
   1962        1.1   mycroft     /* Remember qid across invocations */
   1963        1.1   mycroft     static u_int32_t oqid = 0;
   1964        1.1   mycroft 
   1965        1.1   mycroft     /* timestamp the request/response */
   1966        1.1   mycroft     gettimeofday(&tp, 0);
   1967        1.1   mycroft 
   1968        1.1   mycroft     /*
   1969        1.1   mycroft      * Check if it is a query or a response
   1970        1.1   mycroft      */
   1971        1.1   mycroft     if (datalen == QLEN) {
   1972        1.1   mycroft 	type = QUERY;
   1973       1.11       wiz 	logit(LOG_DEBUG, 0, "Initial traceroute query rcvd from %s to %s",
   1974       1.14       dsl 	    inet_fmt(src), inet_fmt(dst));
   1975        1.1   mycroft     }
   1976        1.1   mycroft     else if ((datalen - QLEN) % RLEN == 0) {
   1977        1.1   mycroft 	type = RESP;
   1978       1.11       wiz 	logit(LOG_DEBUG, 0, "In-transit traceroute query rcvd from %s to %s",
   1979       1.14       dsl 	    inet_fmt(src), inet_fmt(dst));
   1980        1.3   mycroft 	if (IN_MULTICAST(ntohl(dst))) {
   1981       1.11       wiz 	    logit(LOG_DEBUG, 0, "Dropping multicast response");
   1982        1.1   mycroft 	    return;
   1983        1.1   mycroft 	}
   1984        1.1   mycroft     }
   1985        1.1   mycroft     else {
   1986       1.11       wiz 	logit(LOG_WARNING, 0, "%s from %s to %s",
   1987        1.8       wiz 	    "Non decipherable traceroute request received",
   1988       1.14       dsl 	    inet_fmt(src), inet_fmt(dst));
   1989        1.1   mycroft 	return;
   1990        1.1   mycroft     }
   1991        1.1   mycroft 
   1992        1.1   mycroft     qry = (struct tr_query *)data;
   1993        1.1   mycroft 
   1994        1.1   mycroft     /*
   1995        1.1   mycroft      * if it is a packet with all reports filled, drop it
   1996        1.1   mycroft      */
   1997  1.17.28.1       jym     if ((u_int)(rcount = (datalen - QLEN)/RLEN) == no) {
   1998       1.11       wiz 	logit(LOG_DEBUG, 0, "packet with all reports filled in");
   1999        1.1   mycroft 	return;
   2000        1.1   mycroft     }
   2001        1.1   mycroft 
   2002       1.13    itojun     logit(LOG_DEBUG, 0, "s: %s g: %s d: %s ",
   2003       1.14       dsl 	    inet_fmt(qry->tr_src),
   2004       1.14       dsl 	    inet_fmt(group),
   2005       1.14       dsl 	    inet_fmt(qry->tr_dst));
   2006       1.11       wiz     logit(LOG_DEBUG, 0, "rttl: %d rd: %s", qry->tr_rttl,
   2007       1.14       dsl 	    inet_fmt(qry->tr_raddr));
   2008       1.11       wiz     logit(LOG_DEBUG, 0, "rcount:%d, qid:%06x", rcount, qry->tr_qid);
   2009        1.1   mycroft 
   2010        1.1   mycroft     /* determine the routing table entry for this traceroute */
   2011        1.1   mycroft     rt = determine_route(qry->tr_src);
   2012        1.1   mycroft     if (rt) {
   2013       1.11       wiz 	logit(LOG_DEBUG, 0, "rt parent vif: %d rtr: %s metric: %d",
   2014       1.14       dsl 		rt->rt_parent, inet_fmt(rt->rt_gateway),
   2015       1.13    itojun 		rt->rt_metric);
   2016       1.11       wiz 	logit(LOG_DEBUG, 0, "rt origin %s",
   2017       1.14       dsl 		inet_fmts(rt->rt_origin, rt->rt_originmask));
   2018        1.1   mycroft     } else
   2019       1.11       wiz 	logit(LOG_DEBUG, 0, "...no route");
   2020        1.1   mycroft 
   2021        1.1   mycroft     /*
   2022        1.1   mycroft      * Query type packet - check if rte exists
   2023        1.1   mycroft      * Check if the query destination is a vif connected to me.
   2024        1.1   mycroft      * and if so, whether I should start response back
   2025        1.1   mycroft      */
   2026        1.1   mycroft     if (type == QUERY) {
   2027        1.3   mycroft 	if (oqid == qry->tr_qid) {
   2028        1.3   mycroft 	    /*
   2029        1.3   mycroft 	     * If the multicast router is a member of the group being
   2030        1.3   mycroft 	     * queried, and the query is multicasted, then the router can
   2031        1.8       wiz 	     * receive multiple copies of the same query.  If we have already
   2032        1.3   mycroft 	     * replied to this traceroute, just ignore it this time.
   2033        1.3   mycroft 	     *
   2034        1.3   mycroft 	     * This is not a total solution, but since if this fails you
   2035        1.3   mycroft 	     * only get N copies, N <= the number of interfaces on the router,
   2036        1.3   mycroft 	     * it is not fatal.
   2037        1.3   mycroft 	     */
   2038       1.11       wiz 	    logit(LOG_DEBUG, 0, "ignoring duplicate traceroute packet");
   2039        1.3   mycroft 	    return;
   2040        1.3   mycroft 	}
   2041        1.3   mycroft 
   2042        1.1   mycroft 	if (rt == NULL) {
   2043       1.11       wiz 	    logit(LOG_DEBUG, 0, "Mcast traceroute: no route entry %s",
   2044       1.14       dsl 		   inet_fmt(qry->tr_src));
   2045        1.1   mycroft 	    if (IN_MULTICAST(ntohl(dst)))
   2046        1.1   mycroft 		return;
   2047        1.1   mycroft 	}
   2048        1.1   mycroft 	vifi = find_vif(qry->tr_dst, 0);
   2049        1.1   mycroft 
   2050        1.1   mycroft 	if (vifi == NO_VIF) {
   2051        1.1   mycroft 	    /* The traceroute destination is not on one of my subnet vifs. */
   2052       1.11       wiz 	    logit(LOG_DEBUG, 0, "Destination %s not an interface",
   2053       1.14       dsl 		   inet_fmt(qry->tr_dst));
   2054        1.1   mycroft 	    if (IN_MULTICAST(ntohl(dst)))
   2055        1.1   mycroft 		return;
   2056        1.1   mycroft 	    errcode = TR_WRONG_IF;
   2057        1.1   mycroft 	} else if (rt != NULL && !VIFM_ISSET(vifi, rt->rt_children)) {
   2058       1.13    itojun 	    logit(LOG_DEBUG, 0,
   2059       1.13    itojun 		    "Destination %s not on forwarding tree for src %s",
   2060       1.14       dsl 		   inet_fmt(qry->tr_dst),
   2061       1.14       dsl 		   inet_fmt(qry->tr_src));
   2062        1.1   mycroft 	    if (IN_MULTICAST(ntohl(dst)))
   2063        1.1   mycroft 		return;
   2064        1.1   mycroft 	    errcode = TR_WRONG_IF;
   2065        1.1   mycroft 	}
   2066        1.1   mycroft     }
   2067        1.1   mycroft     else {
   2068        1.1   mycroft 	/*
   2069        1.1   mycroft 	 * determine which interface the packet came in on
   2070        1.1   mycroft 	 * RESP packets travel hop-by-hop so this either traversed
   2071        1.1   mycroft 	 * a tunnel or came from a directly attached mrouter.
   2072        1.1   mycroft 	 */
   2073        1.1   mycroft 	if ((vifi = find_vif(src, dst)) == NO_VIF) {
   2074       1.11       wiz 	    logit(LOG_DEBUG, 0, "Wrong interface for packet");
   2075        1.1   mycroft 	    errcode = TR_WRONG_IF;
   2076        1.1   mycroft 	}
   2077        1.1   mycroft     }
   2078        1.1   mycroft 
   2079        1.3   mycroft     /* Now that we've decided to send a response, save the qid */
   2080        1.3   mycroft     oqid = qry->tr_qid;
   2081        1.3   mycroft 
   2082       1.11       wiz     logit(LOG_DEBUG, 0, "Sending traceroute response");
   2083        1.1   mycroft 
   2084        1.1   mycroft     /* copy the packet to the sending buffer */
   2085        1.1   mycroft     p = send_buf + MIN_IP_HEADER_LEN + IGMP_MINLEN;
   2086        1.1   mycroft 
   2087        1.1   mycroft     bcopy(data, p, datalen);
   2088        1.1   mycroft 
   2089        1.1   mycroft     p += datalen;
   2090        1.1   mycroft 
   2091        1.1   mycroft     /*
   2092        1.1   mycroft      * If there is no room to insert our reply, coopt the previous hop
   2093        1.1   mycroft      * error indication to relay this fact.
   2094        1.1   mycroft      */
   2095        1.1   mycroft     if (p + sizeof(struct tr_resp) > send_buf + RECV_BUF_SIZE) {
   2096        1.1   mycroft 	resp = (struct tr_resp *)p - 1;
   2097        1.1   mycroft 	resp->tr_rflags = TR_NO_SPACE;
   2098        1.1   mycroft 	rt = NULL;
   2099        1.1   mycroft 	goto sendit;
   2100        1.1   mycroft     }
   2101        1.1   mycroft 
   2102        1.1   mycroft     /*
   2103        1.1   mycroft      * fill in initial response fields
   2104        1.1   mycroft      */
   2105        1.1   mycroft     resp = (struct tr_resp *)p;
   2106        1.1   mycroft     bzero(resp, sizeof(struct tr_resp));
   2107        1.1   mycroft     datalen += RLEN;
   2108        1.1   mycroft 
   2109        1.3   mycroft     resp->tr_qarr    = htonl((tp.tv_sec + JAN_1970) << 16) +
   2110        1.1   mycroft 				((tp.tv_usec >> 4) & 0xffff);
   2111        1.1   mycroft 
   2112        1.1   mycroft     resp->tr_rproto  = PROTO_DVMRP;
   2113        1.1   mycroft     if (errcode != TR_NO_ERR) {
   2114        1.1   mycroft 	resp->tr_rflags	 = errcode;
   2115        1.1   mycroft 	rt = NULL;	/* hack to enforce send straight to requestor */
   2116        1.1   mycroft 	goto sendit;
   2117        1.1   mycroft     }
   2118        1.1   mycroft     resp->tr_outaddr = uvifs[vifi].uv_lcl_addr;
   2119        1.1   mycroft     resp->tr_fttl    = uvifs[vifi].uv_threshold;
   2120        1.1   mycroft     resp->tr_rflags  = TR_NO_ERR;
   2121        1.1   mycroft 
   2122        1.1   mycroft     /*
   2123        1.1   mycroft      * obtain # of packets out on interface
   2124        1.1   mycroft      */
   2125        1.1   mycroft     v_req.vifi = vifi;
   2126        1.6       hwr     if (ioctl(igmp_socket, SIOCGETVIFCNT, (char *)&v_req) >= 0)
   2127        1.3   mycroft 	resp->tr_vifout  =  htonl(v_req.ocount);
   2128        1.1   mycroft 
   2129        1.1   mycroft     /*
   2130        1.1   mycroft      * fill in scoping & pruning information
   2131        1.1   mycroft      */
   2132        1.1   mycroft     if (rt)
   2133        1.1   mycroft 	for (gt = rt->rt_groups; gt; gt = gt->gt_next) {
   2134        1.1   mycroft 	    if (gt->gt_mcastgrp >= group)
   2135        1.1   mycroft 		break;
   2136        1.1   mycroft 	}
   2137        1.1   mycroft     else
   2138        1.1   mycroft 	gt = NULL;
   2139        1.1   mycroft 
   2140        1.1   mycroft     if (gt && gt->gt_mcastgrp == group) {
   2141        1.1   mycroft 	sg_req.src.s_addr = qry->tr_src;
   2142        1.1   mycroft 	sg_req.grp.s_addr = group;
   2143        1.6       hwr 	if (ioctl(igmp_socket, SIOCGETSGCNT, (char *)&sg_req) >= 0)
   2144        1.3   mycroft 	    resp->tr_pktcnt = htonl(sg_req.pktcnt);
   2145        1.1   mycroft 
   2146        1.1   mycroft 	if (VIFM_ISSET(vifi, gt->gt_scope))
   2147        1.1   mycroft 	    resp->tr_rflags = TR_SCOPED;
   2148        1.1   mycroft 	else if (gt->gt_prsent_timer)
   2149        1.1   mycroft 	    resp->tr_rflags = TR_PRUNED;
   2150        1.5      ross 	else if (!VIFM_ISSET(vifi, gt->gt_grpmems)) {
   2151        1.1   mycroft 	    if (VIFM_ISSET(vifi, rt->rt_children) &&
   2152        1.1   mycroft 		!VIFM_ISSET(vifi, rt->rt_leaves))
   2153        1.1   mycroft 		resp->tr_rflags = TR_OPRUNED;
   2154        1.1   mycroft 	    else
   2155        1.1   mycroft 		resp->tr_rflags = TR_NO_FWD;
   2156        1.5      ross 	}
   2157        1.1   mycroft     } else {
   2158        1.1   mycroft 	if (scoped_addr(vifi, group))
   2159        1.1   mycroft 	    resp->tr_rflags = TR_SCOPED;
   2160        1.3   mycroft 	else if (rt && !VIFM_ISSET(vifi, rt->rt_children))
   2161        1.1   mycroft 	    resp->tr_rflags = TR_NO_FWD;
   2162        1.1   mycroft     }
   2163        1.1   mycroft 
   2164        1.1   mycroft     /*
   2165        1.1   mycroft      *  if no rte exists, set NO_RTE error
   2166        1.1   mycroft      */
   2167        1.1   mycroft     if (rt == NULL) {
   2168        1.1   mycroft 	src = dst;		/* the dst address of resp. pkt */
   2169        1.1   mycroft 	resp->tr_inaddr   = 0;
   2170        1.1   mycroft 	resp->tr_rflags   = TR_NO_RTE;
   2171        1.1   mycroft 	resp->tr_rmtaddr  = 0;
   2172        1.1   mycroft     } else {
   2173        1.1   mycroft 	/* get # of packets in on interface */
   2174        1.1   mycroft 	v_req.vifi = rt->rt_parent;
   2175        1.6       hwr 	if (ioctl(igmp_socket, SIOCGETVIFCNT, (char *)&v_req) >= 0)
   2176        1.3   mycroft 	    resp->tr_vifin = htonl(v_req.icount);
   2177        1.1   mycroft 
   2178        1.1   mycroft 	MASK_TO_VAL(rt->rt_originmask, resp->tr_smask);
   2179        1.1   mycroft 	src = uvifs[rt->rt_parent].uv_lcl_addr;
   2180        1.1   mycroft 	resp->tr_inaddr = src;
   2181        1.1   mycroft 	resp->tr_rmtaddr = rt->rt_gateway;
   2182        1.1   mycroft 	if (!VIFM_ISSET(vifi, rt->rt_children)) {
   2183       1.13    itojun 	    logit(LOG_DEBUG, 0,
   2184       1.13    itojun 		    "Destination %s not on forwarding tree for src %s",
   2185       1.14       dsl 		   inet_fmt(qry->tr_dst),
   2186       1.14       dsl 		   inet_fmt(qry->tr_src));
   2187        1.1   mycroft 	    resp->tr_rflags = TR_WRONG_IF;
   2188        1.1   mycroft 	}
   2189        1.1   mycroft 	if (rt->rt_metric >= UNREACHABLE) {
   2190        1.1   mycroft 	    resp->tr_rflags = TR_NO_RTE;
   2191        1.1   mycroft 	    /* Hack to send reply directly */
   2192        1.1   mycroft 	    rt = NULL;
   2193        1.1   mycroft 	}
   2194        1.1   mycroft     }
   2195        1.1   mycroft 
   2196        1.1   mycroft sendit:
   2197        1.1   mycroft     /*
   2198        1.1   mycroft      * if metric is 1 or no. of reports is 1, send response to requestor
   2199        1.1   mycroft      * else send to upstream router.  If the upstream router can't handle
   2200        1.1   mycroft      * mtrace, set an error code and send to requestor anyway.
   2201        1.1   mycroft      */
   2202       1.11       wiz     logit(LOG_DEBUG, 0, "rcount:%d, no:%d", rcount, no);
   2203        1.1   mycroft 
   2204  1.17.28.1       jym     if (((u_int)(rcount + 1) == no) || (rt == NULL) || (rt->rt_metric == 1)) {
   2205        1.1   mycroft 	resptype = IGMP_MTRACE_REPLY;
   2206        1.1   mycroft 	dst = qry->tr_raddr;
   2207        1.1   mycroft     } else
   2208        1.1   mycroft 	if (!can_mtrace(rt->rt_parent, rt->rt_gateway)) {
   2209        1.1   mycroft 	    dst = qry->tr_raddr;
   2210        1.1   mycroft 	    resp->tr_rflags = TR_OLD_ROUTER;
   2211        1.1   mycroft 	    resptype = IGMP_MTRACE_REPLY;
   2212        1.1   mycroft 	} else {
   2213        1.1   mycroft 	    dst = rt->rt_gateway;
   2214        1.1   mycroft 	    resptype = IGMP_MTRACE_QUERY;
   2215        1.1   mycroft 	}
   2216        1.1   mycroft 
   2217        1.1   mycroft     if (IN_MULTICAST(ntohl(dst))) {
   2218        1.3   mycroft 	/*
   2219        1.3   mycroft 	 * Send the reply on a known multicast capable vif.
   2220        1.3   mycroft 	 * If we don't have one, we can't source any multicasts anyway.
   2221        1.1   mycroft 	 */
   2222        1.3   mycroft 	if (phys_vif != -1) {
   2223       1.11       wiz 	    logit(LOG_DEBUG, 0, "Sending reply to %s from %s",
   2224       1.14       dsl 		inet_fmt(dst), inet_fmt(uvifs[phys_vif].uv_lcl_addr));
   2225        1.3   mycroft 	    k_set_ttl(qry->tr_rttl);
   2226        1.3   mycroft 	    send_igmp(uvifs[phys_vif].uv_lcl_addr, dst,
   2227        1.3   mycroft 		      resptype, no, group,
   2228        1.3   mycroft 		      datalen);
   2229        1.3   mycroft 	    k_set_ttl(1);
   2230        1.3   mycroft 	} else
   2231       1.11       wiz 	    logit(LOG_INFO, 0, "No enabled phyints -- %s",
   2232        1.3   mycroft 			"dropping traceroute reply");
   2233        1.3   mycroft     } else {
   2234       1.11       wiz 	logit(LOG_DEBUG, 0, "Sending %s to %s from %s",
   2235        1.3   mycroft 	    resptype == IGMP_MTRACE_REPLY ?  "reply" : "request on",
   2236       1.14       dsl 	    inet_fmt(dst), inet_fmt(src));
   2237        1.3   mycroft 
   2238        1.1   mycroft 	send_igmp(src, dst,
   2239        1.1   mycroft 		  resptype, no, group,
   2240        1.1   mycroft 		  datalen);
   2241        1.3   mycroft     }
   2242        1.1   mycroft     return;
   2243        1.1   mycroft }
   2244