File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / pimd / route.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Mon Jun 12 07:59:37 2017 UTC (7 years ago) by misho
Branches: pimd, MAIN
CVS tags: v2_3_2, HEAD
pimd 2.3.2

    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.1.1.1 2017/06/12 07:59:37 misho 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>