Annotation of embedaddon/pimd/route.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Copyright (c) 1998-2001
                      3:  * University of Southern California/Information Sciences Institute.
                      4:  * All rights reserved.
                      5:  *
                      6:  * Redistribution and use in source and binary forms, with or without
                      7:  * modification, are permitted provided that the following conditions
                      8:  * are met:
                      9:  * 1. Redistributions of source code must retain the above copyright
                     10:  *    notice, this list of conditions and the following disclaimer.
                     11:  * 2. Redistributions in binary form must reproduce the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer in the
                     13:  *    documentation and/or other materials provided with the distribution.
                     14:  * 3. Neither the name of the project nor the names of its contributors
                     15:  *    may be used to endorse or promote products derived from this software
                     16:  *    without specific prior written permission.
                     17:  *
                     18:  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
                     19:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     20:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     21:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
                     22:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     23:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     24:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     25:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     26:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     27:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     28:  * SUCH DAMAGE.
                     29:  */
                     30: /*
                     31:  *  $Id: route.c,v 1.39 2003/02/12 21:56:55 pavlin Exp $
                     32:  */
                     33: 
                     34: 
                     35: #include "defs.h"
                     36: 
                     37: 
                     38: /* Marian Stagarescu : 07/31/01:
                     39:  *
                     40:  * Administrative scoped multicast filtering im PIMD.  This allows an
                     41:  * interface to be configured as an administrative boundary for the
                     42:  * specified scoped address.  Packets belonging to the scoped address will
                     43:  * not be forwarded.
                     44:  *
                     45:  * Please note the in order to minimize the search for the matching groups
                     46:  * the implementation is limited to:
                     47:  *
                     48:  * Packets are stopped from being forwarded by installing a NULL outgoing
                     49:  * interface; the user space (pimd) is not up-call-ed any more for
                     50:  * these packets which are dropped by kernel (nil oif) except for
                     51:  * when we de-install the route are re-create it (timer 3 minute).
                     52:  * uses the VIF acl that was installed via config scoped statements.
                     53:  *
                     54:  * this is not an all-purpose packet filtering mechanism.
                     55:  * we tried here to achieve the filtering with minimal processing
                     56:  * (inspect (g) when we are about to install a route for it).
                     57:  *
                     58:  * to use it edit pimd.conf and compile with -DSCOPED_ACL
                     59:  */
                     60: 
                     61: static void   process_cache_miss  (struct igmpmsg *igmpctl);
                     62: static void   process_wrong_iif   (struct igmpmsg *igmpctl);
                     63: static void   process_whole_pkt   (char *buf);
                     64: 
                     65: #ifdef SCOPED_ACL
                     66: /* from mrouted. Contributed by Marian Stagarescu <marian@bile.cidera.com>*/
                     67: static int scoped_addr(vifi_t vifi, uint32_t addr)
                     68: {
                     69:     struct vif_acl *acl;
                     70: 
                     71:     for (acl = uvifs[vifi].uv_acl; acl; acl = acl->acl_next) {
                     72:        if ((addr & acl->acl_mask) == acl->acl_addr)
                     73:            return 1;
                     74:     }
                     75: 
                     76:     return 0;
                     77: }
                     78: 
                     79: /* Contributed by Marian Stagarescu <marian@bile.cidera.com>
                     80:  * adapted from mrouted: check for scoped multicast addresses
                     81:  * install null oif if matched
                     82:  */
                     83: #define APPLY_SCOPE(g, mp) {                   \
                     84:        vifi_t i;                               \
                     85:        for (i = 0; i < numvifs; i++)           \
                     86:            if (scoped_addr(i, g))              \
                     87:                (mp)->oifs = 0;                 \
                     88:     }
                     89: #endif  /* SCOPED_ACL */
                     90: 
                     91: /* Return the iif for given address */
                     92: vifi_t get_iif(uint32_t address)
                     93: {
                     94:     struct rpfctl rpfc;
                     95: 
                     96:     k_req_incoming(address, &rpfc);
                     97:     if (rpfc.rpfneighbor.s_addr == INADDR_ANY_N)
                     98:        return NO_VIF;
                     99: 
                    100:     return rpfc.iif;
                    101: }
                    102: 
                    103: /* Return the PIM neighbor toward a source */
                    104: /* If route not found or if a local source or if a directly connected source,
                    105:  * but is not PIM router, or if the first hop router is not a PIM router,
                    106:  * then return NULL.
                    107:  */
                    108: pim_nbr_entry_t *find_pim_nbr(uint32_t source)
                    109: {
                    110:     struct rpfctl rpfc;
                    111:     pim_nbr_entry_t *nbr;
                    112:     uint32_t addr;
                    113: 
                    114:     if (local_address(source) != NO_VIF)
                    115:        return NULL;
                    116:     k_req_incoming(source, &rpfc);
                    117: 
                    118:     if ((rpfc.rpfneighbor.s_addr == INADDR_ANY_N) || (rpfc.iif == NO_VIF))
                    119:        return NULL;
                    120: 
                    121:     /* Figure out the nexthop neighbor by checking the reverse path */
                    122:     addr = rpfc.rpfneighbor.s_addr;
                    123:     for (nbr = uvifs[rpfc.iif].uv_pim_neighbors; nbr; nbr = nbr->next)
                    124:        if (nbr->address == addr)
                    125:            return nbr;
                    126: 
                    127:     return NULL;
                    128: }
                    129: 
                    130: 
                    131: /* TODO: check again the exact setup if the source is local or directly
                    132:  * connected!!!
                    133:  */
                    134: /* TODO: XXX: change the metric and preference for all (S,G) entries per
                    135:  * source or RP?
                    136:  */
                    137: /* TODO - If possible, this would be the place to correct set the
                    138:  * source's preference and metric to that obtained from the kernel
                    139:  * and/or unicast routing protocol.  For now, set it to the configured
                    140:  * default for local pref/metric.
                    141:  */
                    142: 
                    143: /*
                    144:  * Set the iif, upstream router, preference and metric for the route
                    145:  * toward the source. Return TRUE is the route was found, othewise FALSE.
                    146:  * If type==PIM_IIF_SOURCE and if the source is directly connected
                    147:  * then the "upstream" is set to NULL. If srcentry==PIM_IIF_RP, then
                    148:  * "upstream" in case of directly connected "source" will be that "source"
                    149:  * (if it is also PIM router).,
                    150:  */
                    151: int set_incoming(srcentry_t *src, int type)
                    152: {
                    153:     struct rpfctl rpfc;
                    154:     uint32_t src_addr = src->address;
                    155:     uint32_t nbr_addr;
                    156:     struct uvif *vif;
                    157:     pim_nbr_entry_t *nbr;
                    158: 
                    159:     /* Preference will be 0 if directly connected */
                    160:     src->metric = 0;
                    161:     src->preference = 0;
                    162: 
                    163:     /* The source is a local address */
                    164:     src->incoming = local_address(src_addr);
                    165:     if (src->incoming != NO_VIF) {
                    166:        /* iif of (*,G) at RP has to be register_if */
                    167:        if (type == PIM_IIF_RP)
                    168:            src->incoming = reg_vif_num;
                    169: 
                    170:        /* TODO: set the upstream to myself? */
                    171:        src->upstream = NULL;
                    172:        return TRUE;
                    173:     }
                    174: 
                    175:     src->incoming = find_vif_direct(src_addr);
                    176:     if (src->incoming != NO_VIF) {
                    177:        /* The source is directly connected. Check whether we are
                    178:         * looking for real source or RP */
                    179:        if (type == PIM_IIF_SOURCE) {
                    180:            src->upstream = NULL;
                    181:            return TRUE;
                    182:        }
                    183: 
                    184:        /* PIM_IIF_RP */
                    185:        nbr_addr = src_addr;
                    186:     } else {
                    187:        /* TODO: probably need to check the case if the iif is disabled */
                    188:        /* Use the lastest resource: the kernel unicast routing table */
                    189:        k_req_incoming(src_addr, &rpfc);
                    190:        if ((rpfc.iif == NO_VIF) || rpfc.rpfneighbor.s_addr == INADDR_ANY_N) {
                    191:            /* couldn't find a route */
                    192:            if (!IN_LINK_LOCAL_RANGE(src_addr)) {
                    193:                IF_DEBUG(DEBUG_PIM_MRT | DEBUG_RPF)
                    194:                    logit(LOG_DEBUG, 0, "NO ROUTE found for %s", inet_fmt(src_addr, s1, sizeof(s1)));
                    195:            }
                    196:            return FALSE;
                    197:        }
                    198: 
                    199:        src->incoming = rpfc.iif;
                    200:        nbr_addr      = rpfc.rpfneighbor.s_addr;
                    201: 
                    202:        /* set the preference for sources that aren't directly connected. */
                    203:        vif = &uvifs[src->incoming];
                    204:        src->preference = vif->uv_local_pref;
                    205:        src->metric     = vif->uv_local_metric;
                    206:     }
                    207: 
                    208:     /* The upstream router must be a (PIM router) neighbor, otherwise we
                    209:      * are in big trouble ;-) */
                    210:     vif = &uvifs[src->incoming];
                    211:     for (nbr = vif->uv_pim_neighbors; nbr; nbr = nbr->next) {
                    212:        if (ntohl(nbr_addr) < ntohl(nbr->address))
                    213:            continue;
                    214: 
                    215:        if (nbr_addr == nbr->address) {
                    216:            /* The upstream router is found in the list of neighbors.
                    217:             * We are safe! */
                    218:            src->upstream = nbr;
                    219:            IF_DEBUG(DEBUG_RPF)
                    220:                logit(LOG_DEBUG, 0, "For src %s, iif is %d, next hop router is %s",
                    221:                      inet_fmt(src_addr, s1, sizeof(s1)), src->incoming,
                    222:                      inet_fmt(nbr_addr, s2, sizeof(s2)));
                    223: 
                    224:            return TRUE;
                    225:        }
                    226: 
                    227:        break;
                    228:     }
                    229: 
                    230:     /* TODO: control the number of messages! */
                    231:     logit(LOG_INFO, 0, "For src %s, iif is %d, next hop router is %s: NOT A PIM ROUTER",
                    232:          inet_fmt(src_addr, s1, sizeof(s1)), src->incoming,
                    233:          inet_fmt(nbr_addr, s2, sizeof(s2)));
                    234:     src->upstream = NULL;
                    235: 
                    236:     return FALSE;
                    237: }
                    238: 
                    239: 
                    240: /*
                    241:  * TODO: XXX: currently `source` is not used. Will be used with IGMPv3 where
                    242:  * we have source-specific Join/Prune.
                    243:  */
                    244: void add_leaf(vifi_t vifi, uint32_t source, uint32_t group)
                    245: {
                    246:     mrtentry_t *mrt;
                    247:     mrtentry_t *srcs;
                    248:     vifbitmap_t old_oifs;
                    249:     vifbitmap_t new_oifs;
                    250:     vifbitmap_t new_leaves;
                    251: 
                    252:     /* Don't create routing entries for the LAN scoped addresses */
                    253:     if (ntohl(group) <= INADDR_MAX_LOCAL_GROUP) { /* group <= 224.0.0.255? */
                    254:        IF_DEBUG(DEBUG_IGMP)
                    255:            logit(LOG_DEBUG, 0, "Not creating routing entry for LAN scoped group %s",
                    256:                  inet_fmt(group, s1, sizeof(s1)));
                    257:        return;
                    258:     }
                    259: 
                    260:     /*
                    261:      * XXX: only if I am a DR, the IGMP Join should result in creating
                    262:      * a PIM MRT state.
                    263:      * XXX: Each router must know if it has local members, i.e., whether
                    264:      * it is a last-hop router as well. This info is needed so it will
                    265:      * know whether is allowed to initiate a SPT switch by sending
                    266:      * a PIM (S,G) Join to the high datarate source.
                    267:      * However, if a non-DR last-hop router has not received
                    268:      * a PIM Join, it should not create a PIM state, otherwise later
                    269:      * this state may incorrectly trigger PIM joins.
                    270:      * There is a design flow in pimd, so without making major changes
                    271:      * the best we can do is that the non-DR last-hop router will
                    272:      * record the local members only after it receives PIM Join from the DR
                    273:      * (i.e.  after the second or third IGMP Join by the local member).
                    274:      * The downside is that a last-hop router may delay the initiation
                    275:      * of the SPT switch. Sigh...
                    276:      */
                    277:     if (IN_PIM_SSM_RANGE(group))
                    278:        mrt = find_route(source, group, MRTF_SG, CREATE);
                    279:     else if (uvifs[vifi].uv_flags & VIFF_DR)
                    280:        mrt = find_route(INADDR_ANY_N, group, MRTF_WC, CREATE);
                    281:     else
                    282:        mrt = find_route(INADDR_ANY_N, group, MRTF_WC, DONT_CREATE);
                    283: 
                    284:     if (!mrt)
                    285:        return;
                    286: 
                    287:     IF_DEBUG(DEBUG_MRT)
                    288:        logit(LOG_DEBUG, 0, "Adding vif %d for group %s", vifi, inet_fmt(group, s1, sizeof(s1)));
                    289: 
                    290:     if (VIFM_ISSET(vifi, mrt->leaves))
                    291:        return;     /* Already a leaf */
                    292: 
                    293:     calc_oifs(mrt, &old_oifs);
                    294:     VIFM_COPY(mrt->leaves, new_leaves);
                    295:     VIFM_SET(vifi, new_leaves);    /* Add the leaf */
                    296:     change_interfaces(mrt,
                    297:                      mrt->incoming,
                    298:                      mrt->joined_oifs,
                    299:                      mrt->pruned_oifs,
                    300:                      new_leaves,
                    301:                      mrt->asserted_oifs, 0);
                    302:     calc_oifs(mrt, &new_oifs);
                    303: 
                    304:     /* Only if I am the DR for that subnet, eventually initiate a Join */
                    305:     if (!(uvifs[vifi].uv_flags & VIFF_DR))
                    306:        return;
                    307: 
                    308:     if ((mrt->flags & MRTF_NEW) || (VIFM_ISEMPTY(old_oifs) && (!VIFM_ISEMPTY(new_oifs)))) {
                    309:        /* A new created entry or the oifs have changed
                    310:         * from NULL to non-NULL. */
                    311:        mrt->flags &= ~MRTF_NEW;
                    312:        FIRE_TIMER(mrt->jp_timer); /* Timeout the Join/Prune timer */
                    313: 
                    314:        /* TODO: explicitly call the function below?
                    315:        send_pim_join_prune(mrt->upstream->vifi,
                    316:                            mrt->upstream,
                    317:                            PIM_JOIN_PRUNE_HOLDTIME);
                    318:        */
                    319:     }
                    320: 
                    321:     /* Check all (S,G) entries and set the inherited "leaf" flag.
                    322:      * TODO: XXX: This won't work for IGMPv3, because there we don't know
                    323:      * whether the (S,G) leaf oif was inherited from the (*,G) entry or
                    324:      * was created by source specific IGMP join.
                    325:      */
                    326:     for (srcs = mrt->group->mrtlink; srcs; srcs = srcs->grpnext) {
                    327:        VIFM_COPY(srcs->leaves, new_leaves);
                    328:        VIFM_SET(vifi, new_leaves);
                    329:        change_interfaces(srcs,
                    330:                          srcs->incoming,
                    331:                          srcs->joined_oifs,
                    332:                          srcs->pruned_oifs,
                    333:                          new_leaves,
                    334:                          srcs->asserted_oifs, 0);
                    335:     }
                    336: }
                    337: 
                    338: 
                    339: /*
                    340:  * TODO: XXX: currently `source` is not used. To be used with IGMPv3 where
                    341:  * we have source-specific joins/prunes.
                    342:  */
                    343: void delete_leaf(vifi_t vifi, uint32_t source, uint32_t group)
                    344: {
                    345:     mrtentry_t *mrt;
                    346:     mrtentry_t *srcs;
                    347:     vifbitmap_t new_oifs;
                    348:     vifbitmap_t old_oifs;
                    349:     vifbitmap_t new_leaves;
                    350: 
                    351:     if (IN_PIM_SSM_RANGE(group))
                    352:        mrt = find_route(source, group, MRTF_SG, DONT_CREATE);
                    353:     else
                    354:        mrt = find_route(INADDR_ANY_N, group, MRTF_WC, DONT_CREATE);
                    355: 
                    356:     if (!mrt)
                    357:        return;
                    358: 
                    359:     if (!VIFM_ISSET(vifi, mrt->leaves))
                    360:        return;      /* This interface wasn't leaf */
                    361: 
                    362:     IF_DEBUG(DEBUG_MRT)
                    363:        logit(LOG_DEBUG, 0, "Deleting vif %d for group %s", vifi, inet_fmt(group, s1, sizeof(s1)));
                    364: 
                    365:     calc_oifs(mrt, &old_oifs);
                    366: 
                    367:     /* For SSM, source must match */
                    368:     if (!IN_PIM_SSM_RANGE(group) || (mrt->source->address==source)) {
                    369:        VIFM_COPY(mrt->leaves, new_leaves);
                    370:        VIFM_CLR(vifi, new_leaves);
                    371:        change_interfaces(mrt,
                    372:                          mrt->incoming,
                    373:                          mrt->joined_oifs,
                    374:                          mrt->pruned_oifs,
                    375:                          new_leaves,
                    376:                          mrt->asserted_oifs, 0);
                    377:     }
                    378:     calc_oifs(mrt, &new_oifs);
                    379: 
                    380:     if ((!VIFM_ISEMPTY(old_oifs)) && VIFM_ISEMPTY(new_oifs)) {
                    381:        /* The result oifs have changed from non-NULL to NULL */
                    382:        FIRE_TIMER(mrt->jp_timer); /* Timeout the Join/Prune timer */
                    383: 
                    384:        /* TODO: explicitly call the function below?
                    385:        send_pim_join_prune(mrt->upstream->vifi,
                    386:                            mrt->upstream,
                    387:                            PIM_JOIN_PRUNE_HOLDTIME);
                    388:        */
                    389:     }
                    390: 
                    391:     /* Check all (S,G) entries and clear the inherited "leaf" flag.
                    392:      * TODO: XXX: This won't work for IGMPv3, because there we don't know
                    393:      * whether the (S,G) leaf oif was inherited from the (*,G) entry or
                    394:      * was created by source specific IGMP join.
                    395:      */
                    396:     for (srcs = mrt->group->mrtlink; srcs; srcs = srcs->grpnext) {
                    397:        VIFM_COPY(srcs->leaves, new_leaves);
                    398:        VIFM_CLR(vifi, new_leaves);
                    399:        change_interfaces(srcs,
                    400:                          srcs->incoming,
                    401:                          srcs->joined_oifs,
                    402:                          srcs->pruned_oifs,
                    403:                          new_leaves,
                    404:                          srcs->asserted_oifs, 0);
                    405:     }
                    406: }
                    407: 
                    408: 
                    409: void calc_oifs(mrtentry_t *mrt, vifbitmap_t *oifs_ptr)
                    410: {
                    411:     vifbitmap_t oifs;
                    412:     mrtentry_t *grp;
                    413:     mrtentry_t *mrp;
                    414: 
                    415:     /*
                    416:      * oifs =
                    417:      * (((copied_outgoing + my_join) - my_prune) + my_leaves)
                    418:      *              - my_asserted_oifs - incoming_interface,
                    419:      * i.e. `leaves` have higher priority than `prunes`, but lower priority
                    420:      * than `asserted`. The incoming interface is always deleted from the oifs
                    421:      */
                    422: 
                    423:     if (!mrt) {
                    424:        VIFM_CLRALL(*oifs_ptr);
                    425:        return;
                    426:     }
                    427: 
                    428:     VIFM_CLRALL(oifs);
                    429:     if (!(mrt->flags & MRTF_PMBR)) {
                    430:        /* Either (*,G) or (S,G). Merge with the oifs from the (*,*,RP) */
                    431:        mrp = mrt->group->active_rp_grp->rp->rpentry->mrtlink;
                    432:        if (mrp) {
                    433:            VIFM_MERGE(oifs, mrp->joined_oifs, oifs);
                    434:            VIFM_CLR_MASK(oifs, mrp->pruned_oifs);
                    435:            VIFM_MERGE(oifs, mrp->leaves, oifs);
                    436:            VIFM_CLR_MASK(oifs, mrp->asserted_oifs);
                    437:        }
                    438:     }
                    439:     if (mrt->flags & MRTF_SG) {
                    440:        /* (S,G) entry. Merge with the oifs from (*,G) */
                    441:        grp = mrt->group->grp_route;
                    442:        if (grp) {
                    443:            VIFM_MERGE(oifs, grp->joined_oifs, oifs);
                    444:            VIFM_CLR_MASK(oifs, grp->pruned_oifs);
                    445:            VIFM_MERGE(oifs, grp->leaves, oifs);
                    446:            VIFM_CLR_MASK(oifs, grp->asserted_oifs);
                    447:        }
                    448:     }
                    449: 
                    450:     /* Calculate my own stuff */
                    451:     VIFM_MERGE(oifs, mrt->joined_oifs, oifs);
                    452:     VIFM_CLR_MASK(oifs, mrt->pruned_oifs);
                    453:     VIFM_MERGE(oifs, mrt->leaves, oifs);
                    454:     VIFM_CLR_MASK(oifs, mrt->asserted_oifs);
                    455: 
                    456:     VIFM_COPY(oifs, *oifs_ptr);
                    457: }
                    458: 
                    459: /*
                    460:  * Set the iif, join/prune/leaves/asserted interfaces. Calculate and
                    461:  * set the oifs.
                    462:  * Return 1 if oifs change from NULL to not-NULL.
                    463:  * Return -1 if oifs change from non-NULL to NULL
                    464:  *  else return 0
                    465:  * If the iif change or if the oifs change from NULL to non-NULL
                    466:  * or vice-versa, then schedule that mrtentry join/prune timer to
                    467:  * timeout immediately.
                    468:  */
                    469: int change_interfaces(mrtentry_t *mrt,
                    470:                      vifi_t new_iif,
                    471:                      vifbitmap_t new_joined_oifs_,
                    472:                      vifbitmap_t new_pruned_oifs,
                    473:                      vifbitmap_t new_leaves_,
                    474:                      vifbitmap_t new_asserted_oifs,
                    475:                      uint16_t flags)
                    476: {
                    477:     vifbitmap_t new_joined_oifs;  /* The oifs for that particular mrtentry */
                    478:     vifbitmap_t old_joined_oifs __attribute__ ((unused));
                    479:     vifbitmap_t old_pruned_oifs __attribute__ ((unused));
                    480:     vifbitmap_t old_leaves __attribute__ ((unused));
                    481:     vifbitmap_t new_leaves;
                    482:     vifbitmap_t old_asserted_oifs __attribute__ ((unused));
                    483:     vifbitmap_t new_real_oifs;    /* The result oifs */
                    484:     vifbitmap_t old_real_oifs;
                    485:     vifi_t      old_iif;
                    486:     rpentry_t   *rp;
                    487:     cand_rp_t   *cand_rp;
                    488:     kernel_cache_t *kc;
                    489:     rp_grp_entry_t *rp_grp;
                    490:     grpentry_t     *grp;
                    491:     mrtentry_t     *srcs;
                    492:     mrtentry_t     *mwc;
                    493:     mrtentry_t     *mrp;
                    494:     int delete_mrt_flag;
                    495:     int result;
                    496:     int fire_timer_flag;
                    497: 
                    498:     if (!mrt)
                    499:        return 0;
                    500: 
                    501:     VIFM_COPY(new_joined_oifs_, new_joined_oifs);
                    502:     VIFM_COPY(new_leaves_, new_leaves);
                    503: 
                    504:     old_iif = mrt->incoming;
                    505:     VIFM_COPY(mrt->joined_oifs, old_joined_oifs);
                    506:     VIFM_COPY(mrt->leaves, old_leaves);
                    507:     VIFM_COPY(mrt->pruned_oifs, old_pruned_oifs);
                    508:     VIFM_COPY(mrt->asserted_oifs, old_asserted_oifs);
                    509: 
                    510:     VIFM_COPY(mrt->oifs, old_real_oifs);
                    511: 
                    512:     mrt->incoming = new_iif;
                    513:     VIFM_COPY(new_joined_oifs, mrt->joined_oifs);
                    514:     VIFM_COPY(new_pruned_oifs, mrt->pruned_oifs);
                    515:     VIFM_COPY(new_leaves, mrt->leaves);
                    516:     VIFM_COPY(new_asserted_oifs, mrt->asserted_oifs);
                    517:     calc_oifs(mrt, &new_real_oifs);
                    518: 
                    519:     if (VIFM_ISEMPTY(old_real_oifs)) {
                    520:        if (VIFM_ISEMPTY(new_real_oifs))
                    521:            result = 0;
                    522:        else
                    523:            result = 1;
                    524:     } else {
                    525:        if (VIFM_ISEMPTY(new_real_oifs))
                    526:            result = -1;
                    527:        else
                    528:            result = 0;
                    529:     }
                    530: 
                    531:     if ((VIFM_SAME(new_real_oifs, old_real_oifs))
                    532:        && (new_iif == old_iif)
                    533:        && !(flags & MFC_UPDATE_FORCE))
                    534:        return 0;               /* Nothing to change */
                    535: 
                    536:     if ((result != 0) || (new_iif != old_iif) || (flags & MFC_UPDATE_FORCE)) {
                    537:        FIRE_TIMER(mrt->jp_timer);
                    538:     }
                    539:     VIFM_COPY(new_real_oifs, mrt->oifs);
                    540: 
                    541:     if (mrt->flags & MRTF_PMBR) {
                    542:        /* (*,*,RP) entry */
                    543:        rp = mrt->source;
                    544:        if (!rp)
                    545:            return 0;           /* Shouldn't happen */
                    546: 
                    547:        rp->incoming = new_iif;
                    548:        cand_rp = rp->cand_rp;
                    549: 
                    550:        if (VIFM_ISEMPTY(new_real_oifs)) {
                    551:            delete_mrt_flag = TRUE;
                    552:        } else {
                    553:            delete_mrt_flag = FALSE;
                    554: #ifdef RSRR
                    555:            rsrr_cache_send(mrt, RSRR_NOTIFICATION_OK);
                    556: #endif /* RSRR */
                    557:        }
                    558: 
                    559:        if (mrt->flags & MRTF_KERNEL_CACHE) {
                    560:            /* Update the kernel MFC entries */
                    561:            if (delete_mrt_flag == TRUE) {
                    562:                /* XXX: no need to send RSRR message. Will do it when
                    563:                 * delete the mrtentry.
                    564:                 */
                    565:                for (kc = mrt->kernel_cache; kc; kc = kc->next)
                    566:                    delete_mrtentry_all_kernel_cache(mrt);
                    567:            } else {
                    568:                /* here mrt->source->address is the RP address */
                    569:                for (kc = mrt->kernel_cache; kc; kc = kc->next)
                    570:                    k_chg_mfc(igmp_socket, kc->source,
                    571:                              kc->group, new_iif,
                    572:                              new_real_oifs, mrt->source->address);
                    573:            }
                    574:        }
                    575: 
                    576:        /*
                    577:         * Update all (*,G) entries associated with this RP.
                    578:         * The particular (*,G) outgoing are not changed, but the change
                    579:         * in the (*,*,RP) oifs may have affect the real oifs.
                    580:         */
                    581:        fire_timer_flag = FALSE;
                    582:        for (rp_grp = cand_rp->rp_grp_next; rp_grp; rp_grp = rp_grp->rp_grp_next) {
                    583:            for (grp = rp_grp->grplink; grp; grp = grp->rpnext) {
                    584:                if (grp->grp_route) {
                    585:                    if (change_interfaces(grp->grp_route, new_iif,
                    586:                                          grp->grp_route->joined_oifs,
                    587:                                          grp->grp_route->pruned_oifs,
                    588:                                          grp->grp_route->leaves,
                    589:                                          grp->grp_route->asserted_oifs,
                    590:                                          flags))
                    591:                        fire_timer_flag = TRUE;
                    592:                } else {
                    593:                    /* Change all (S,G) entries if no (*,G) */
                    594:                    for (srcs = grp->mrtlink; srcs; srcs = srcs->grpnext) {
                    595:                        if (srcs->flags & MRTF_RP) {
                    596:                            if (change_interfaces(srcs, new_iif,
                    597:                                                  srcs->joined_oifs,
                    598:                                                  srcs->pruned_oifs,
                    599:                                                  srcs->leaves,
                    600:                                                  srcs->asserted_oifs,
                    601:                                                  flags))
                    602:                                fire_timer_flag = TRUE;
                    603:                        } else {
                    604:                            if (change_interfaces(srcs,
                    605:                                                  srcs->incoming,
                    606:                                                  srcs->joined_oifs,
                    607:                                                  srcs->pruned_oifs,
                    608:                                                  srcs->leaves,
                    609:                                                  srcs->asserted_oifs,
                    610:                                                  flags))
                    611:                                fire_timer_flag = TRUE;
                    612:                        }
                    613:                    }
                    614:                }
                    615:            }
                    616:        }
                    617:        if (fire_timer_flag == TRUE)
                    618:            FIRE_TIMER(mrt->jp_timer);
                    619:        if (delete_mrt_flag == TRUE) {
                    620:            /* TODO: XXX: trigger a Prune message? Don't delete now, it will
                    621:             * be automatically timed out. If want to delete now, don't
                    622:             * reference to it anymore!
                    623:            delete_mrtentry(mrt);
                    624:            */
                    625:        }
                    626: 
                    627:        return result;   /* (*,*,RP) */
                    628:     }
                    629: 
                    630:     if (mrt->flags & MRTF_WC) {
                    631:        /* (*,G) entry */
                    632:        if (VIFM_ISEMPTY(new_real_oifs)) {
                    633:            delete_mrt_flag = TRUE;
                    634:        } else {
                    635:            delete_mrt_flag = FALSE;
                    636: #ifdef RSRR
                    637:            rsrr_cache_send(mrt, RSRR_NOTIFICATION_OK);
                    638: #endif /* RSRR */
                    639:        }
                    640: 
                    641:        if (mrt->flags & MRTF_KERNEL_CACHE) {
                    642:            if (delete_mrt_flag == TRUE) {
                    643:                delete_mrtentry_all_kernel_cache(mrt);
                    644:            } else {
                    645:                for (kc = mrt->kernel_cache; kc; kc = kc->next)
                    646:                    k_chg_mfc(igmp_socket, kc->source,
                    647:                              kc->group, new_iif,
                    648:                              new_real_oifs, mrt->group->rpaddr);
                    649:            }
                    650:        }
                    651: 
                    652:        /* Update all (S,G) entries for this group.
                    653:         * For the (S,G)RPbit entries the iif is the iif toward the RP;
                    654:         * The particular (S,G) oifs are not changed, but the change in the
                    655:         * (*,G) oifs may affect the real oifs.
                    656:         */
                    657:        fire_timer_flag = FALSE;
                    658:        for (srcs = mrt->group->mrtlink; srcs; srcs = srcs->grpnext) {
                    659:            if (srcs->flags & MRTF_RP) {
                    660:                if (change_interfaces(srcs, new_iif,
                    661:                                      srcs->joined_oifs,
                    662:                                      srcs->pruned_oifs,
                    663:                                      srcs->leaves,
                    664:                                      srcs->asserted_oifs, flags))
                    665:                    fire_timer_flag = TRUE;
                    666:            } else {
                    667:                if (change_interfaces(srcs, srcs->incoming,
                    668:                                      srcs->joined_oifs,
                    669:                                      srcs->pruned_oifs,
                    670:                                      srcs->leaves,
                    671:                                      srcs->asserted_oifs, flags))
                    672:                    fire_timer_flag = TRUE;
                    673:            }
                    674:        }
                    675: 
                    676:        if (fire_timer_flag == TRUE)
                    677:            FIRE_TIMER(mrt->jp_timer);
                    678: 
                    679:        if (delete_mrt_flag == TRUE) {
                    680:            /* TODO: XXX: the oifs are NULL. Send a Prune message? */
                    681:        }
                    682: 
                    683:        return result;          /* (*,G) */
                    684:     }
                    685: 
                    686:     /* (S,G) entry */
                    687:     if (mrt->flags & MRTF_SG) {
                    688:        mrp = mrt->group->active_rp_grp->rp->rpentry->mrtlink;
                    689:        mwc = mrt->group->grp_route;
                    690: 
                    691: #ifdef KERNEL_MFC_WC_G
                    692:        mrtentry_t *tmp;
                    693: 
                    694:        /* Check whether (*,*,RP) or (*,G) have different (iif,oifs) from
                    695:         * the (S,G). If "yes", then forbid creating (*,G) MFC. */
                    696:        for (tmp = mrp; 1; tmp = mwc) {
                    697:            while (1) {
                    698:                vifbitmap_t oifs;
                    699: 
                    700:                if (!tmp)
                    701:                    break;
                    702: 
                    703:                if (tmp->flags & MRTF_MFC_CLONE_SG)
                    704:                    break;
                    705: 
                    706:                if (tmp->incoming != mrt->incoming) {
                    707:                    delete_single_kernel_cache_addr(tmp, INADDR_ANY_N, mrt->group->group);
                    708:                    tmp->flags |= MRTF_MFC_CLONE_SG;
                    709:                    break;
                    710:                }
                    711: 
                    712:                calc_oifs(tmp, &oifs);
                    713:                if (!(VIFM_SAME(new_real_oifs, oifs)))
                    714:                    tmp->flags |= MRTF_MFC_CLONE_SG;
                    715: 
                    716:                break;
                    717:            }
                    718: 
                    719:            if (tmp == mwc)
                    720:                break;
                    721:        }
                    722: #endif /* KERNEL_MFC_WC_G */
                    723: 
                    724:        if (VIFM_ISEMPTY(new_real_oifs)) {
                    725:            delete_mrt_flag = TRUE;
                    726:        } else {
                    727:            delete_mrt_flag = FALSE;
                    728: #ifdef RSRR
                    729:            rsrr_cache_send(mrt, RSRR_NOTIFICATION_OK);
                    730: #endif
                    731:        }
                    732: 
                    733:        if (mrt->flags & MRTF_KERNEL_CACHE) {
                    734:            if (delete_mrt_flag == TRUE)
                    735:                delete_mrtentry_all_kernel_cache(mrt);
                    736:            else
                    737:                k_chg_mfc(igmp_socket, mrt->source->address,
                    738:                          mrt->group->group, new_iif, new_real_oifs,
                    739:                          mrt->group->rpaddr);
                    740:        }
                    741: 
                    742:        if (old_iif != new_iif) {
                    743:            if (new_iif == mrt->source->incoming) {
                    744:                /* For example, if this was (S,G)RPbit with iif toward the RP,
                    745:                 * and now switch to the Shortest Path.
                    746:                 * The setup of MRTF_SPT flag must be
                    747:                 * done by the external calling function (triggered only
                    748:                 * by receiving of a data from the source.)
                    749:                 */
                    750:                mrt->flags &= ~MRTF_RP;
                    751:                /* TODO: XXX: delete? Check again where will be the best
                    752:                 * place to set it.
                    753:                mrt->flags |= MRTF_SPT;
                    754:                */
                    755:            }
                    756: 
                    757:            if ((mwc && mwc->incoming == new_iif) ||
                    758:                (mrp && mrp->incoming == new_iif)) {
                    759:                /* If the new iif points toward the RP, reset the SPT flag.
                    760:                 * (PIM-SM-spec-10.ps pp. 11, 2.10, last sentence of first
                    761:                 * paragraph. */
                    762: 
                    763:                /* TODO: XXX: check again! */
                    764:                mrt->flags &= ~MRTF_SPT;
                    765:                mrt->flags |= MRTF_RP;
                    766:            }
                    767:        }
                    768: 
                    769:        /* TODO: XXX: if this is (S,G)RPbit entry and the oifs==(*,G)oifs,
                    770:         * then delete the (S,G) entry?? The same if we have (*,*,RP) ? */
                    771:        if (delete_mrt_flag == TRUE) {
                    772:            /* TODO: XXX: the oifs are NULL. Send a Prune message ? */
                    773:        }
                    774: 
                    775:        /* TODO: XXX: have the feeling something is missing.... */
                    776:        return result;          /* (S,G) */
                    777:     }
                    778: 
                    779:     return result;
                    780: }
                    781: 
                    782: 
                    783: /* TODO: implement it. Required to allow changing of the physical interfaces
                    784:  * configuration without need to restart pimd.
                    785:  */
                    786: int delete_vif_from_mrt(vifi_t vifi __attribute__((unused)))
                    787: {
                    788:     return TRUE;
                    789: }
                    790: 
                    791: 
                    792: void process_kernel_call(void)
                    793: {
                    794:     struct igmpmsg *igmpctl = (struct igmpmsg *)igmp_recv_buf;
                    795: 
                    796:     switch (igmpctl->im_msgtype) {
                    797:        case IGMPMSG_NOCACHE:
                    798:            process_cache_miss(igmpctl);
                    799:            break;
                    800: 
                    801:        case IGMPMSG_WRONGVIF:
                    802:            process_wrong_iif(igmpctl);
                    803:            break;
                    804: 
                    805:        case IGMPMSG_WHOLEPKT:
                    806:            process_whole_pkt(igmp_recv_buf);
                    807:            break;
                    808: 
                    809:        default:
                    810:            IF_DEBUG(DEBUG_KERN)
                    811:                logit(LOG_DEBUG, 0, "Unknown IGMP message type from kernel: %d", igmpctl->im_msgtype);
                    812:            break;
                    813:     }
                    814: }
                    815: 
                    816: 
                    817: /*
                    818:  * TODO: when cache miss, check the iif, because probably ASSERTS
                    819:  * shoult take place
                    820:  */
                    821: static void process_cache_miss(struct igmpmsg *igmpctl)
                    822: {
                    823:     uint32_t source, mfc_source;
                    824:     uint32_t group;
                    825:     uint32_t rp_addr;
                    826:     vifi_t iif;
                    827:     mrtentry_t *mrt;
                    828:     mrtentry_t *mrp;
                    829: 
                    830:     /* When there is a cache miss, we check only the header of the packet
                    831:      * (and only it should be sent up by the kernel. */
                    832: 
                    833:     group  = igmpctl->im_dst.s_addr;
                    834:     source = mfc_source = igmpctl->im_src.s_addr;
                    835:     iif    = igmpctl->im_vif;
                    836: 
                    837:     IF_DEBUG(DEBUG_MRT)
                    838:        logit(LOG_DEBUG, 0, "Cache miss, src %s, dst %s, iif %d",
                    839:              inet_fmt(source, s1, sizeof(s1)), inet_fmt(group, s2, sizeof(s2)), iif);
                    840: 
                    841:     /* TODO: XXX: check whether the kernel generates cache miss for the LAN scoped addresses */
                    842:     if (ntohl(group) <= INADDR_MAX_LOCAL_GROUP)
                    843:        return; /* Don't create routing entries for the LAN scoped addresses */
                    844: 
                    845:     /* TODO: check if correct in case the source is one of my addresses */
                    846:     /* If I am the DR for this source, create (S,G) and add the register_vif
                    847:      * to the oifs. */
                    848: 
                    849:     if ((uvifs[iif].uv_flags & VIFF_DR) && (find_vif_direct_local(source) == iif)) {
                    850:        mrt = find_route(source, group, MRTF_SG, CREATE);
                    851:        if (!mrt)
                    852:            return;
                    853: 
                    854:        mrt->flags &= ~MRTF_NEW;
                    855:        /* set reg_vif_num as outgoing interface ONLY if I am not the RP */
                    856:        if (mrt->group->rpaddr != my_cand_rp_address)
                    857:            VIFM_SET(reg_vif_num, mrt->joined_oifs);
                    858:        change_interfaces(mrt,
                    859:                          mrt->incoming,
                    860:                          mrt->joined_oifs,
                    861:                          mrt->pruned_oifs,
                    862:                          mrt->leaves,
                    863:                          mrt->asserted_oifs, 0);
                    864:     } else {
                    865:        mrt = find_route(source, group, MRTF_SG | MRTF_WC | MRTF_PMBR, DONT_CREATE);
                    866:        switch_shortest_path(source, group);
                    867:        if (!mrt)
                    868:            return;
                    869:     }
                    870: 
                    871:     /* TODO: if there are too many cache miss for the same (S,G),
                    872:      * install negative cache entry in the kernel (oif==NULL) to prevent
                    873:      * too many upcalls. */
                    874: 
                    875:     if (mrt->incoming == iif) {
                    876:        if (!VIFM_ISEMPTY(mrt->oifs)) {
                    877:            if (mrt->flags & MRTF_SG) {
                    878:                /* TODO: check that the RPbit is not set? */
                    879:                /* TODO: XXX: TIMER implem. dependency! */
                    880:                if (mrt->timer < PIM_DATA_TIMEOUT)
                    881:                    SET_TIMER(mrt->timer, PIM_DATA_TIMEOUT);
                    882: 
                    883:                if (!(mrt->flags & MRTF_SPT)) {
                    884:                    mrp = mrt->group->grp_route;
                    885:                    if (!mrp)
                    886:                        mrp = mrt->group->active_rp_grp->rp->rpentry->mrtlink;
                    887: 
                    888:                    if (mrp) {
                    889:                        /* Check if the (S,G) iif is different from
                    890:                         * the (*,G) or (*,*,RP) iif */
                    891:                        if ((mrt->incoming != mrp->incoming) ||
                    892:                            (mrt->upstream != mrp->upstream)) {
                    893:                            mrt->flags |= MRTF_SPT;
                    894:                            mrt->flags &= ~MRTF_RP;
                    895:                        }
                    896:                    }
                    897:                }
                    898:            }
                    899: 
                    900:            if (mrt->flags & MRTF_PMBR)
                    901:                rp_addr = mrt->source->address;
                    902:            else
                    903:                rp_addr = mrt->group->rpaddr;
                    904: 
                    905:            mfc_source = source;
                    906: #ifdef KERNEL_MFC_WC_G
                    907:            if (mrt->flags & (MRTF_WC | MRTF_PMBR))
                    908:                if (!(mrt->flags & MRTF_MFC_CLONE_SG))
                    909:                    mfc_source = INADDR_ANY_N;
                    910: #endif /* KERNEL_MFC_WC_G */
                    911: 
                    912:            add_kernel_cache(mrt, mfc_source, group, MFC_MOVE_FORCE);
                    913: 
                    914: #ifdef SCOPED_ACL
                    915:            APPLY_SCOPE(group, mrt);
                    916: #endif
                    917:            k_chg_mfc(igmp_socket, mfc_source, group, iif, mrt->oifs, rp_addr);
                    918: 
                    919:            /* No need for RSRR message, because nothing has changed. */
                    920:        }
                    921: 
                    922:        return;                 /* iif match */
                    923:     }
                    924: 
                    925:     /* The iif doesn't match */
                    926:     if (mrt->flags & MRTF_SG) {
                    927:        /* Arrived on wrong interface */
                    928:        if (mrt->flags & MRTF_SPT)
                    929:            return;
                    930: 
                    931:        mrp = mrt->group->grp_route;
                    932:        if (!mrp)
                    933:            mrp = mrt->group->active_rp_grp->rp->rpentry->mrtlink;
                    934: 
                    935:        if (mrp) {
                    936:            /* Forward on (*,G) or (*,*,RP) */
                    937:            if (mrp->incoming == iif) {
                    938: #ifdef KERNEL_MFC_WC_G
                    939:                if (!(mrp->flags & MRTF_MFC_CLONE_SG))
                    940:                    mfc_source = INADDR_ANY_N;
                    941: #endif /* KERNEL_MFC_WC_G */
                    942: 
                    943:                add_kernel_cache(mrp, mfc_source, group, 0);
                    944: 
                    945: #ifdef SCOPED_ACL
                    946:                /* marian: not sure if we reach here with our scoped traffic? */
                    947:                APPLY_SCOPE(group, mrt);
                    948: #endif
                    949:                k_chg_mfc(igmp_socket, mfc_source, group, iif,
                    950:                          mrp->oifs, mrt->group->rpaddr);
                    951: #ifdef RSRR
                    952:                rsrr_cache_send(mrp, RSRR_NOTIFICATION_OK);
                    953: #endif /* RSRR */
                    954:            }
                    955:        }
                    956:     }
                    957: }
                    958: 
                    959: 
                    960: /*
                    961:  * A multicast packet has been received on wrong iif by the kernel.
                    962:  * Check for a matching entry. If there is (S,G) with reset SPTbit and
                    963:  * the packet was received on the iif toward the source, this completes
                    964:  * the switch to the shortest path and triggers (S,G) prune toward the RP
                    965:  * (unless I am the RP).
                    966:  * Otherwise, if the packet's iif is in the oiflist of the routing entry,
                    967:  * trigger an Assert.
                    968:  */
                    969: static void process_wrong_iif(struct igmpmsg *igmpctl)
                    970: {
                    971:     uint32_t source;
                    972:     uint32_t group;
                    973:     vifi_t  iif;
                    974:     mrtentry_t *mrt;
                    975: 
                    976:     group  = igmpctl->im_dst.s_addr;
                    977:     source = igmpctl->im_src.s_addr;
                    978:     iif    = igmpctl->im_vif;
                    979: 
                    980:     IF_DEBUG(DEBUG_MRT)
                    981:        logit(LOG_DEBUG, 0, "Wrong iif: src %s, dst %s, iif %d",
                    982:              inet_fmt(source, s1, sizeof(s1)), inet_fmt(group, s2, sizeof(s2)), iif);
                    983: 
                    984:     /* Don't create routing entries for the LAN scoped addresses */
                    985:     if (ntohl(group) <= INADDR_MAX_LOCAL_GROUP)
                    986:        return;
                    987: 
                    988:     /* Ignore if it comes on register vif. register vif is neither SPT iif,
                    989:      * neither is used to send asserts out.
                    990:      */
                    991:     if (uvifs[iif].uv_flags & VIFF_REGISTER)
                    992:        return;
                    993: 
                    994:     mrt = find_route(source, group, MRTF_SG | MRTF_WC | MRTF_PMBR, DONT_CREATE);
                    995:     if (!mrt)
                    996:        return;
                    997: 
                    998:     /*
                    999:      * TODO: check again!
                   1000:      */
                   1001:     if (mrt->flags & MRTF_SG) {
                   1002:        if (!(mrt->flags & MRTF_SPT)) {
                   1003:            if (mrt->source->incoming == iif) {
                   1004:                /* Switch to the Shortest Path */
                   1005:                mrt->flags |= MRTF_SPT;
                   1006:                mrt->flags &= ~MRTF_RP;
                   1007:                add_kernel_cache(mrt, source, group, MFC_MOVE_FORCE);
                   1008:                k_chg_mfc(igmp_socket, source, group, iif,
                   1009:                          mrt->oifs, mrt->group->rpaddr);
                   1010:                FIRE_TIMER(mrt->jp_timer);
                   1011: #ifdef RSRR
                   1012:                rsrr_cache_send(mrt, RSRR_NOTIFICATION_OK);
                   1013: #endif /* RSRR */
                   1014: 
                   1015:                return;
                   1016:            }
                   1017:        }
                   1018:     }
                   1019: 
                   1020:     /* Trigger an Assert */
                   1021:     if (VIFM_ISSET(iif, mrt->oifs))
                   1022:        send_pim_assert(source, group, iif, mrt);
                   1023: }
                   1024: 
                   1025: /*
                   1026:  * Receives whole packets from the register vif entries
                   1027:  * in the kernel, and calls the send_pim_register procedure to
                   1028:  * encapsulate the packets and unicasts them to the RP.
                   1029:  */
                   1030: static void process_whole_pkt(char *buf)
                   1031: {
                   1032:     send_pim_register((char *)(buf + sizeof(struct igmpmsg)));
                   1033: }
                   1034: 
                   1035: 
                   1036: mrtentry_t *switch_shortest_path(uint32_t source, uint32_t group)
                   1037: {
                   1038:     mrtentry_t *mrt;
                   1039: 
                   1040:     IF_DEBUG(DEBUG_MRT)
                   1041:        logit(LOG_DEBUG, 0, "Switch shortest path (SPT): src %s, group %s",
                   1042:              inet_fmt(source, s1, sizeof(s1)), inet_fmt(group, s2, sizeof(s2)));
                   1043: 
                   1044:     /* TODO: XXX: prepare and send immediately the (S,G) join? */
                   1045:     mrt = find_route(source, group, MRTF_SG, CREATE);
                   1046:     if (mrt) {
                   1047:        if (mrt->flags & MRTF_NEW) {
                   1048:            mrt->flags &= ~MRTF_NEW;
                   1049:        } else if (mrt->flags & MRTF_RP || IN_PIM_SSM_RANGE(group)) {
                   1050:            /* (S,G)RPbit with iif toward RP. Reset to (S,G) with iif
                   1051:             * toward S. Delete the kernel cache (if any), because
                   1052:             * change_interfaces() will reset it with iif toward S
                   1053:             * and no data will arrive from RP before the switch
                   1054:             * really occurs.
                   1055:              * For SSM, (S,G)RPbit entry does not exist but switch to
                   1056:              * SPT must be allowed right away.
                   1057:             */
                   1058:            mrt->flags &= ~MRTF_RP;
                   1059:            mrt->incoming = mrt->source->incoming;
                   1060:            mrt->upstream = mrt->source->upstream;
                   1061:            delete_mrtentry_all_kernel_cache(mrt);
                   1062:            change_interfaces(mrt,
                   1063:                              mrt->incoming,
                   1064:                              mrt->joined_oifs,
                   1065:                              mrt->pruned_oifs,
                   1066:                              mrt->leaves,
                   1067:                              mrt->asserted_oifs, 0);
                   1068:        }
                   1069: 
                   1070:        SET_TIMER(mrt->timer, PIM_DATA_TIMEOUT);
                   1071:        FIRE_TIMER(mrt->jp_timer);
                   1072:     }
                   1073: 
                   1074:     return mrt;
                   1075: }
                   1076: 
                   1077: /**
                   1078:  * Local Variables:
                   1079:  *  version-control: t
                   1080:  *  indent-tabs-mode: t
                   1081:  *  c-file-style: "ellemtel"
                   1082:  *  c-basic-offset: 4
                   1083:  * End:
                   1084:  */

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