Annotation of embedaddon/mrouted/prune.c, revision 1.1

1.1     ! misho       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>