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