File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / mrouted / prune.c
Revision 1.1: download - view: text, annotated - select for diffs - revision graph
Tue Feb 21 23:10:48 2012 UTC (12 years, 4 months ago) by misho
CVS tags: MAIN, HEAD
Initial revision

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>