Annotation of embedaddon/pimd/route.c, revision 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>