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_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_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_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_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_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_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_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_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_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_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_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