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