Annotation of embedaddon/mrouted/prune.c, revision 1.1.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>