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