2 * Copyright (c) 1998 by the University of Southern California.
5 * Permission to use, copy, modify, and distribute this software and
6 * its documentation in source and binary forms for lawful
7 * purposes and without fee is hereby granted, provided
8 * that the above copyright notice appear in all copies and that both
9 * the copyright notice and this permission notice appear in supporting
10 * documentation, and that any documentation, advertising materials,
11 * and other materials related to such distribution and use acknowledge
12 * that the software was developed by the University of Southern
13 * California and/or Information Sciences Institute.
14 * The name of the University of Southern California may not
15 * be used to endorse or promote products derived from this software
16 * without specific prior written permission.
18 * THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
19 * ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
20 * PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
21 * INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
22 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
25 * IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
26 * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
27 * TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
28 * THE USE OR PERFORMANCE OF THIS SOFTWARE.
30 * Other copyrights might apply to parts of this software and are so
31 * noted when applicable.
34 * Questions concerning this software should be directed to
35 * Mickael Hoerdt (hoerdt@clarinet.u-strasbg.fr) LSIIT Strasbourg.
39 * This program has been derived from pim6dd.
40 * The pim6dd program is covered by the license in the accompanying file
41 * named "LICENSE.pim6dd".
44 * This program has been derived from pimd.
45 * The pimd program is covered by the license in the accompanying file
46 * named "LICENSE.pimd".
51 #include <sys/types.h>
57 #include "pim6_proto.h"
64 #include <netinet6/ip6_mroute.h>
65 #include <netinet/ip6.h>
66 #include "routesock.h"
68 static void process_cache_miss __P((struct mrt6msg * im));
69 static void process_wrong_iif __P((struct mrt6msg * im));
70 static void process_whole_pkt __P((char *buf));
72 u_int32 default_source_metric = UCAST_DEFAULT_SOURCE_METRIC;
73 u_int32 default_source_preference = UCAST_DEFAULT_SOURCE_PREFERENCE;
76 /* Return the iif for given address */
80 struct sockaddr_in6 *address;
84 k_req_incoming(address, &rpfc);
85 if (IN6_IS_ADDR_UNSPECIFIED(&rpfc.rpfneighbor.sin6_addr))
90 /* Return the PIM neighbor toward a source */
92 * If route not found or if a local source or if a directly connected source,
93 * but is not PIM router, or if the first hop router is not a PIM router,
98 struct sockaddr_in6 *source;
101 pim_nbr_entry_t *pim_nbr;
102 struct sockaddr_in6 next_hop_router_addr;
104 if (local_address(source) != NO_VIF)
105 return (pim_nbr_entry_t *) NULL;
106 k_req_incoming(source, &rpfc);
107 if((IN6_IS_ADDR_UNSPECIFIED(&rpfc.rpfneighbor.sin6_addr))
108 || (rpfc.iif == NO_VIF))
109 return (pim_nbr_entry_t *) NULL;
110 next_hop_router_addr = rpfc.rpfneighbor;
111 for (pim_nbr = uvifs[rpfc.iif].uv_pim_neighbors;
112 pim_nbr != (pim_nbr_entry_t *) NULL;
113 pim_nbr = pim_nbr->next)
114 if (inet6_equal(&pim_nbr->address,&next_hop_router_addr))
116 return (pim_nbr_entry_t *) NULL;
121 * TODO: check again the exact setup if the source is local or directly
122 * connected!!! Yes Really for Ipv6!!
125 * TODO: XXX: change the metric and preference for all (S,G) entries per
129 * TODO - If possible, this would be the place to correct set the source's
130 * preference and metric to that obtained from the kernel and/or unicast
131 * routing protocol. For now, set it to the configured default for local
136 * Set the iif, upstream router, preference and metric for the route toward
137 * the source. Return TRUE is the route was found, othewise FALSE. If
138 * srctype==PIM_IIF_SOURCE and if the source is directly connected then the
139 * "upstream" is set to NULL. If srcentry==PIM_IIF_RP, then "upstream" in
140 * case of directly connected "source" will be that "source" (if it is also
144 set_incoming(srcentry_ptr, srctype)
145 srcentry_t *srcentry_ptr;
149 struct sockaddr_in6 source = srcentry_ptr->address;
150 struct sockaddr_in6 neighbor_addr;
151 register struct uvif *v;
152 register pim_nbr_entry_t *n;
154 /* Preference will be 0 if directly connected */
156 srcentry_ptr->metric = 0;
157 srcentry_ptr->preference = 0;
159 if ((srcentry_ptr->incoming = local_address(&source)) != NO_VIF)
161 /* The source is a local address */
162 /* TODO: set the upstream to myself? */
163 srcentry_ptr->upstream = (pim_nbr_entry_t *) NULL;
167 if ((srcentry_ptr->incoming = find_vif_direct(&source)) != NO_VIF)
170 * The source is directly connected. Check whether we are looking for
174 if (srctype == PIM_IIF_SOURCE)
176 srcentry_ptr->upstream = (pim_nbr_entry_t *) NULL;
182 neighbor_addr = source;
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(&source, &rpfc);
190 if ((rpfc.iif == NO_VIF) ||
191 IN6_IS_ADDR_UNSPECIFIED(&rpfc.rpfneighbor.sin6_addr))
193 /* couldn't find a route */
194 IF_DEBUG(DEBUG_PIM_MRT | DEBUG_RPF)
195 log(LOG_DEBUG, 0, "NO ROUTE found for %s",
196 inet6_fmt(&source.sin6_addr));
199 srcentry_ptr->incoming = rpfc.iif;
200 neighbor_addr = rpfc.rpfneighbor;
201 /* set the preference for sources that aren't directly connected. */
202 v = &uvifs[srcentry_ptr->incoming];
203 srcentry_ptr->preference = v->uv_local_pref;
204 srcentry_ptr->metric = v->uv_local_metric;
208 * The upstream router must be a (PIM router) neighbor, otherwise we are
209 * in big trouble ;-).
210 * Yes but the neighbors are link-local and the rp is global ipv6..
212 /* WARNING WARNING WARNING WARNING */
213 /* If the router is directly connected to the RP and the RP is the BSR , the next hop is
214 * the globally reachable addresse of the RP : NOT link local neighbor but
215 * a ipv6 global neighbor...
216 * the upstream router is the globally reachable router...
219 /* WARNING WARNING WARNING WARNING */
221 v = &uvifs[srcentry_ptr->incoming];
222 if (inet6_equal(&source,&neighbor_addr))
224 srcentry_ptr->upstream=v->uv_pim_neighbors;
228 for (n = v->uv_pim_neighbors; n != NULL; n = n->next)
230 if (inet6_lessthan(&neighbor_addr,&n->address))
232 if (inet6_equal(&neighbor_addr,&n->address))
235 * The upstream router is found in the list of neighbors. We are
239 srcentry_ptr->upstream = n;
242 "For src %s, iif is %d, next hop router is %s",
243 inet6_fmt(&source.sin6_addr), srcentry_ptr->incoming,
244 inet6_fmt(&neighbor_addr.sin6_addr));
251 /* TODO: control the number of messages! */
253 "For src %s, iif is %d, next hop router is %s: NOT A PIM ROUTER",
254 inet6_fmt(&source.sin6_addr), srcentry_ptr->incoming,
255 inet6_fmt(&neighbor_addr.sin6_addr));
257 srcentry_ptr->upstream = (pim_nbr_entry_t *) NULL;
264 * TODO: XXX: currently `source` is not used. Will be used with IGMPv3 where
265 * we have source-specific Join/Prune.
269 add_leaf(vifi, source, group)
271 struct sockaddr_in6 *source;
272 struct sockaddr_in6 *group;
274 mrtentry_t *mrtentry_ptr;
280 mrtentry_ptr = find_route(&sockaddr6_any, group, MRTF_WC, CREATE);
282 if (mrtentry_ptr == (mrtentry_t *) NULL)
285 if ((mrtentry_ptr->incoming == vifi)
286 && (!(uvifs[vifi].uv_flags & VIFF_DR)))
289 * The report is received on the iif for this routing entry and I am
290 * not the DR for that subnet. Ignore it.
293 if (mrtentry_ptr->flags & MRTF_NEW)
294 delete_mrtentry(mrtentry_ptr);
299 log(LOG_DEBUG, 0, "Adding vif %d for group %s", vifi,
300 inet6_fmt(&group->sin6_addr));
302 if (IF_ISSET(vifi, &mrtentry_ptr->leaves))
303 return; /* Already a leaf */
304 calc_oifs(mrtentry_ptr, &old_oifs);
305 IF_COPY(&mrtentry_ptr->leaves, &new_leaves);
306 IF_SET(vifi, &new_leaves); /* Add the leaf */
307 change_interfaces(mrtentry_ptr,
308 mrtentry_ptr->incoming,
309 &mrtentry_ptr->joined_oifs,
310 &mrtentry_ptr->pruned_oifs,
312 &mrtentry_ptr->asserted_oifs, 0);
313 calc_oifs(mrtentry_ptr, &new_oifs);
315 if ((mrtentry_ptr->flags & MRTF_NEW)
316 || (IF_ISEMPTY(&old_oifs) && (!IF_ISEMPTY(&new_oifs))))
320 * A new created entry or the oifs have changed from NULL to
324 mrtentry_ptr->flags &= ~MRTF_NEW;
325 FIRE_TIMER(mrtentry_ptr->jp_timer); /* Timeout the Join/Prune
328 * TODO: explicitly call the function below?
329 * send_pim6_join_prune(mrtentry_ptr->upstream->vifi,
330 * mrtentry_ptr->upstream, pim_join_prune_holdtime);
337 * TODO: XXX: currently `source` is not used. To be used with IGMPv3 where we
338 * have source-specific joins/prunes.
341 delete_leaf(vifi, source, group)
343 struct sockaddr_in6 *source;
344 struct sockaddr_in6 *group;
346 mrtentry_t *mrtentry_ptr;
347 mrtentry_t *mrtentry_srcs;
352 mrtentry_ptr = find_route(&sockaddr6_any, group, MRTF_WC, DONT_CREATE);
353 if (mrtentry_ptr == (mrtentry_t *) NULL)
356 if (!IF_ISSET(vifi, &mrtentry_ptr->leaves))
357 return; /* This interface wasn't leaf */
359 calc_oifs(mrtentry_ptr, &old_oifs);
360 IF_COPY(&mrtentry_ptr->leaves, &new_leaves);
361 IF_CLR(vifi, &new_leaves);
362 change_interfaces(mrtentry_ptr,
363 mrtentry_ptr->incoming,
364 &mrtentry_ptr->joined_oifs,
365 &mrtentry_ptr->pruned_oifs,
367 &mrtentry_ptr->asserted_oifs, 0);
368 calc_oifs(mrtentry_ptr, &new_oifs);
369 if ((!IF_ISEMPTY(&old_oifs)) && IF_ISEMPTY(&new_oifs))
371 /* The result oifs have changed from non-NULL to NULL */
372 FIRE_TIMER(mrtentry_ptr->jp_timer); /* Timeout the Join/Prune
375 * TODO: explicitly call the function?
376 * send_pim6_join_prune(mrtentry_ptr->upstream->vifi,
377 * mrtentry_ptr->upstream, pim_join_prune_holdtime);
381 * Check all (S,G) entries and clear the inherited "leaf" flag. TODO:
382 * XXX: This won't work for IGMPv3, because there we don't know whether
383 * the (S,G) leaf oif was inherited from the (*,G) entry or was created
384 * by source specific IGMP join.
386 for (mrtentry_srcs = mrtentry_ptr->group->mrtlink;
387 mrtentry_srcs != (mrtentry_t *) NULL;
388 mrtentry_srcs = mrtentry_srcs->grpnext)
390 IF_COPY(&mrtentry_srcs->leaves, &new_leaves);
391 IF_CLR(vifi, &new_leaves);
392 change_interfaces(mrtentry_srcs,
393 mrtentry_srcs->incoming,
394 &mrtentry_srcs->joined_oifs,
395 &mrtentry_srcs->pruned_oifs,
397 &mrtentry_srcs->asserted_oifs, 0);
404 calc_oifs(mrtentry_ptr, oifs_ptr)
405 mrtentry_t *mrtentry_ptr;
409 mrtentry_t *grp_route;
410 mrtentry_t *rp_route;
413 * oifs = (((copied_outgoing + my_join) - my_prune) + my_leaves) -
414 * my_asserted_oifs - incoming_interface, i.e. `leaves` have higher
415 * priority than `prunes`, but lower priority than `asserted`. The
416 * incoming interface is always deleted from the oifs
419 if (mrtentry_ptr == (mrtentry_t *) NULL)
425 if (!(mrtentry_ptr->flags & MRTF_PMBR))
427 /* Either (*,G) or (S,G). Merge with the oifs from the (*,*,RP) */
429 mrtentry_ptr->group->active_rp_grp->rp->rpentry->mrtlink)
430 != (mrtentry_t *) NULL)
432 IF_MERGE(&oifs, &rp_route->joined_oifs, &oifs);
433 IF_CLR_MASK(&oifs, &rp_route->pruned_oifs);
434 IF_MERGE(&oifs, &rp_route->leaves, &oifs);
435 IF_CLR_MASK(&oifs, &rp_route->asserted_oifs);
438 if (mrtentry_ptr->flags & MRTF_SG)
440 /* (S,G) entry. Merge with the oifs from (*,G) */
441 if ((grp_route = mrtentry_ptr->group->grp_route)
442 != (mrtentry_t *) NULL)
444 IF_MERGE(&oifs, &grp_route->joined_oifs, &oifs);
445 IF_CLR_MASK(&oifs, &grp_route->pruned_oifs);
446 IF_MERGE(&oifs, &grp_route->leaves, &oifs);
447 IF_CLR_MASK(&oifs, &grp_route->asserted_oifs);
451 /* Calculate my own stuff */
452 IF_MERGE(&oifs, &mrtentry_ptr->joined_oifs, &oifs);
453 IF_CLR_MASK(&oifs, &mrtentry_ptr->pruned_oifs);
454 IF_MERGE(&oifs, &mrtentry_ptr->leaves, &oifs);
455 IF_CLR_MASK(&oifs, &mrtentry_ptr->asserted_oifs);
457 IF_CLR(mrtentry_ptr->incoming, &oifs);
458 IF_COPY(&oifs, oifs_ptr);
462 * Set the iif, join/prune/leaves/asserted interfaces. Calculate and set the
463 * oifs. Return 1 if oifs change from NULL to not-NULL. Return -1 if oifs
464 * change from non-NULL to NULL else return 0 If the iif change or if the
465 * oifs change from NULL to non-NULL or vice-versa, then schedule that
466 * mrtentry join/prune timer to timeout immediately.
469 change_interfaces(mrtentry_ptr, new_iif, new_joined_oifs_, new_pruned_oifs,
470 new_leaves_, new_asserted_oifs, flags)
471 mrtentry_t *mrtentry_ptr;
473 if_set *new_joined_oifs_;
474 if_set *new_pruned_oifs;
476 if_set *new_asserted_oifs;
479 if_set new_joined_oifs; /* The oifs for that particular
481 if_set old_joined_oifs;
482 if_set old_pruned_oifs;
485 if_set old_asserted_oifs;
486 if_set new_real_oifs; /* The result oifs */
487 if_set old_real_oifs;
489 rpentry_t *rpentry_ptr;
490 cand_rp_t *cand_rp_ptr;
491 kernel_cache_t *kernel_cache_ptr;
492 rp_grp_entry_t *rp_grp_entry_ptr;
493 grpentry_t *grpentry_ptr;
494 mrtentry_t *mrtentry_srcs;
495 mrtentry_t *mrtentry_wc;
496 mrtentry_t *mrtentry_rp;
497 int delete_mrtentry_flag;
501 if (mrtentry_ptr == (mrtentry_t *) NULL)
504 IF_COPY(new_joined_oifs_, &new_joined_oifs);
505 IF_COPY(new_leaves_, &new_leaves);
507 old_iif = mrtentry_ptr->incoming;
508 IF_COPY(&mrtentry_ptr->joined_oifs, &old_joined_oifs);
509 IF_COPY(&mrtentry_ptr->leaves, &old_leaves);
510 IF_COPY(&mrtentry_ptr->pruned_oifs, &old_pruned_oifs);
511 IF_COPY(&mrtentry_ptr->asserted_oifs, &old_asserted_oifs);
513 IF_COPY(&mrtentry_ptr->oifs, &old_real_oifs);
515 mrtentry_ptr->incoming = new_iif;
516 IF_COPY(&new_joined_oifs, &mrtentry_ptr->joined_oifs);
517 IF_COPY(new_pruned_oifs, &mrtentry_ptr->pruned_oifs);
518 IF_COPY(&new_leaves, &mrtentry_ptr->leaves);
519 IF_COPY(new_asserted_oifs, &mrtentry_ptr->asserted_oifs);
520 calc_oifs(mrtentry_ptr, &new_real_oifs);
522 if (IF_ISEMPTY(&old_real_oifs))
524 if (IF_ISEMPTY(&new_real_oifs))
531 if (IF_ISEMPTY(&new_real_oifs))
537 if ((IF_SAME(&new_real_oifs, &old_real_oifs))
538 && (new_iif == old_iif)
539 && !(flags & MFC_UPDATE_FORCE))
540 return 0; /* Nothing to change */
542 if ((return_value != 0) || (new_iif != old_iif)
543 || (flags & MFC_UPDATE_FORCE))
544 FIRE_TIMER(mrtentry_ptr->jp_timer);
546 IF_COPY(&new_real_oifs, &mrtentry_ptr->oifs);
548 if (mrtentry_ptr->flags & MRTF_PMBR)
551 rpentry_ptr = mrtentry_ptr->source;
552 if (rpentry_ptr == (rpentry_t *) NULL)
553 return (0); /* Shoudn't happen */
554 rpentry_ptr->incoming = new_iif;
555 cand_rp_ptr = rpentry_ptr->cand_rp;
557 if (IF_ISEMPTY(&new_real_oifs))
559 delete_mrtentry_flag = TRUE;
563 delete_mrtentry_flag = FALSE;
565 rsrr_cache_send(mrtentry_ptr, RSRR_NOTIFICATION_OK);
569 if (mrtentry_ptr->flags & MRTF_KERNEL_CACHE)
571 /* Update the kernel MFC entries */
572 if (delete_mrtentry_flag == TRUE)
574 * XXX: no need to send RSRR message. Will do it when delete
577 for (kernel_cache_ptr = mrtentry_ptr->kernel_cache;
578 kernel_cache_ptr != (kernel_cache_t *) NULL;
579 kernel_cache_ptr = kernel_cache_ptr->next)
580 delete_mrtentry_all_kernel_cache(mrtentry_ptr);
583 for (kernel_cache_ptr = mrtentry_ptr->kernel_cache;
584 kernel_cache_ptr != (kernel_cache_t *) NULL;
585 kernel_cache_ptr = kernel_cache_ptr->next)
586 /* here mrtentry_ptr->source->address is the RP address */
587 k_chg_mfc(mld6_socket, &kernel_cache_ptr->source,
588 &kernel_cache_ptr->group, new_iif,
589 &new_real_oifs, &mrtentry_ptr->source->address);
594 * Update all (*,G) entries associated with this RP. The particular
595 * (*,G) outgoing are not changed, but the change in the (*,*,RP)
596 * oifs may have affect the real oifs.
598 fire_timer_flag = FALSE;
599 for (rp_grp_entry_ptr = cand_rp_ptr->rp_grp_next;
600 rp_grp_entry_ptr != (rp_grp_entry_t *) NULL;
601 rp_grp_entry_ptr = rp_grp_entry_ptr->rp_grp_next)
603 for (grpentry_ptr = rp_grp_entry_ptr->grplink;
604 grpentry_ptr != (grpentry_t *) NULL;
605 grpentry_ptr = grpentry_ptr->rpnext)
607 if (grpentry_ptr->grp_route != (mrtentry_t *) NULL)
609 if (change_interfaces(grpentry_ptr->grp_route, new_iif,
610 &grpentry_ptr->grp_route->joined_oifs,
611 &grpentry_ptr->grp_route->pruned_oifs,
612 &grpentry_ptr->grp_route->leaves,
613 &grpentry_ptr->grp_route->asserted_oifs,
615 fire_timer_flag = TRUE;
619 /* Change all (S,G) entries if no (*,G) */
620 for (mrtentry_srcs = grpentry_ptr->mrtlink;
621 mrtentry_srcs != (mrtentry_t *) NULL;
622 mrtentry_srcs = mrtentry_srcs->grpnext)
624 if (mrtentry_srcs->flags & MRTF_RP)
626 if (change_interfaces(mrtentry_srcs, new_iif,
627 &mrtentry_srcs->joined_oifs,
628 &mrtentry_srcs->pruned_oifs,
629 &mrtentry_srcs->leaves,
630 &mrtentry_srcs->asserted_oifs,
632 fire_timer_flag = TRUE;
636 if (change_interfaces(mrtentry_srcs,
637 mrtentry_srcs->incoming,
638 &mrtentry_srcs->joined_oifs,
639 &mrtentry_srcs->pruned_oifs,
640 &mrtentry_srcs->leaves,
641 &mrtentry_srcs->asserted_oifs,
643 fire_timer_flag = TRUE;
649 if (fire_timer_flag == TRUE)
650 FIRE_TIMER(mrtentry_ptr->jp_timer);
651 if (delete_mrtentry_flag == TRUE)
654 * TODO: XXX: trigger a Prune message? Don't delete now, it will
655 * be automatically timed out. If want to delete now, don't
656 * reference to it anymore! delete_mrtentry(mrtentry_ptr);
659 return (return_value); /* (*,*,RP) */
662 if (mrtentry_ptr->flags & MRTF_WC)
665 if (IF_ISEMPTY(&new_real_oifs))
666 delete_mrtentry_flag = TRUE;
669 delete_mrtentry_flag = FALSE;
671 rsrr_cache_send(mrtentry_ptr, RSRR_NOTIFICATION_OK);
674 if (mrtentry_ptr->flags & MRTF_KERNEL_CACHE)
676 if (delete_mrtentry_flag == TRUE)
677 delete_mrtentry_all_kernel_cache(mrtentry_ptr);
680 for (kernel_cache_ptr = mrtentry_ptr->kernel_cache;
681 kernel_cache_ptr != (kernel_cache_t *) NULL;
682 kernel_cache_ptr = kernel_cache_ptr->next)
683 k_chg_mfc(mld6_socket, &kernel_cache_ptr->source,
684 &kernel_cache_ptr->group, new_iif,
685 &new_real_oifs, &mrtentry_ptr->group->rpaddr);
689 * Update all (S,G) entries for this group. For the (S,G)RPbit
690 * entries the iif is the iif toward the RP; The particular (S,G)
691 * oifs are not changed, but the change in the (*,G) oifs may affect
694 fire_timer_flag = FALSE;
695 for (mrtentry_srcs = mrtentry_ptr->group->mrtlink;
696 mrtentry_srcs != (mrtentry_t *) NULL;
697 mrtentry_srcs = mrtentry_srcs->grpnext)
699 if (mrtentry_srcs->flags & MRTF_RP)
701 if (change_interfaces(mrtentry_srcs, new_iif,
702 &mrtentry_srcs->joined_oifs,
703 &mrtentry_srcs->pruned_oifs,
704 &mrtentry_srcs->leaves,
705 &mrtentry_srcs->asserted_oifs, flags))
706 fire_timer_flag = TRUE;
710 if (change_interfaces(mrtentry_srcs, mrtentry_srcs->incoming,
711 &mrtentry_srcs->joined_oifs,
712 &mrtentry_srcs->pruned_oifs,
713 &mrtentry_srcs->leaves,
714 &mrtentry_srcs->asserted_oifs, flags))
715 fire_timer_flag = TRUE;
719 if (fire_timer_flag == TRUE)
720 FIRE_TIMER(mrtentry_ptr->jp_timer);
721 if (delete_mrtentry_flag == TRUE)
723 /* TODO: XXX: the oifs are NULL. Send a Prune message? */
725 return (return_value); /* (*,G) */
728 if (mrtentry_ptr->flags & MRTF_SG)
731 #ifdef KERNEL_MFC_WC_G
733 mrtentry_t *mrtentry_tmp;
734 #endif /* KERNEL_MFC_WC_G */
736 mrtentry_rp = mrtentry_ptr->group->active_rp_grp->rp->rpentry->mrtlink;
737 mrtentry_wc = mrtentry_ptr->group->grp_route;
738 #ifdef KERNEL_MFC_WC_G
740 * Check whether (*,*,RP) or (*,G) have different (iif,oifs) from the
741 * (S,G). If "yes", then forbid creating (*,G) MFC.
743 for (mrtentry_tmp = mrtentry_rp; 1; mrtentry_tmp = mrtentry_wc)
747 if (mrtentry_tmp == (mrtentry_t *) NULL)
749 if (mrtentry_tmp->flags & MRTF_MFC_CLONE_SG)
751 if (mrtentry_tmp->incoming != mrtentry_ptr->incoming)
753 delete_single_kernel_cache_addr(mrtentry_tmp, IN6ADDR_ANY_N,
754 mrtentry_ptr->group->group);
755 mrtentry_tmp->flags |= MRTF_MFC_CLONE_SG;
758 calc_oifs(mrtentry_tmp, &tmp_oifs);
759 if (!(IF_SAME(&new_real_oifs, &tmp_oifs)))
760 mrtentry_tmp->flags |= MRTF_MFC_CLONE_SG;
763 if (mrtentry_tmp == mrtentry_wc)
766 #endif /* KERNEL_MFC_WC_G */
768 if (IF_ISEMPTY(&new_real_oifs))
769 delete_mrtentry_flag = TRUE;
772 delete_mrtentry_flag = FALSE;
774 rsrr_cache_send(mrtentry_ptr, RSRR_NOTIFICATION_OK);
777 if (mrtentry_ptr->flags & MRTF_KERNEL_CACHE)
779 if (delete_mrtentry_flag == TRUE)
780 delete_mrtentry_all_kernel_cache(mrtentry_ptr);
783 k_chg_mfc(mld6_socket, &mrtentry_ptr->source->address,
784 &mrtentry_ptr->group->group, new_iif, &new_real_oifs,
785 &mrtentry_ptr->group->rpaddr);
788 if (old_iif != new_iif)
790 if (new_iif == mrtentry_ptr->source->incoming)
793 * For example, if this was (S,G)RPbit with iif toward the
794 * RP, and now switch to the Shortest Path. The setup of
795 * MRTF_SPT flag must be done by the external calling
796 * function (triggered only by receiving of a data from the
799 mrtentry_ptr->flags &= ~MRTF_RP;
801 * TODO: XXX: delete? Check again where will be the best
802 * place to set it. mrtentry_ptr->flags |= MRTF_SPT;
805 if (((mrtentry_wc != (mrtentry_t *) NULL)
806 && (mrtentry_wc->incoming == new_iif))
807 || ((mrtentry_rp != (mrtentry_t *) NULL)
808 && (mrtentry_rp->incoming == new_iif)))
811 * If the new iif points toward the RP, reset the SPT flag.
812 * (PIM-SM-spec-10.ps pp. 11, 2.10, last sentence of first
815 /* TODO: XXX: check again! */
817 mrtentry_ptr->flags &= ~MRTF_SPT;
818 mrtentry_ptr->flags |= MRTF_RP;
822 * TODO: XXX: if this is (S,G)RPbit entry and the oifs==(*,G)oifs,
823 * then delete the (S,G) entry?? The same if we have (*,*,RP) ?
825 if (delete_mrtentry_flag == TRUE)
827 /* TODO: XXX: the oifs are NULL. Send a Prune message ? */
829 /* TODO: XXX: have the feeling something is missing.... */
830 return (return_value); /* (S,G) */
832 return (return_value);
837 * TODO: implement it. Required to allow changing of the physical interfaces
838 * configuration without need to restart pimd.
841 delete_vif_from_mrt(vifi)
849 process_kernel_call()
851 register struct mrt6msg *im; /* igmpmsg control struct */
853 im = (struct mrt6msg *) mld6_recv_buf;
855 switch (im->im6_msgtype)
857 case MRT6MSG_NOCACHE:
858 process_cache_miss(im);
860 case MRT6MSG_WRONGMIF:
861 process_wrong_iif(im);
863 case MRT6MSG_WHOLEPKT:
864 process_whole_pkt(mld6_recv_buf);
868 log(LOG_DEBUG, 0, "Unknown kernel_call code");
875 * TODO: when cache miss, check the iif, because probably ASSERTS shoult take
880 process_cache_miss(im)
883 static struct sockaddr_in6 source = {sizeof(source) , AF_INET6 };
884 static struct sockaddr_in6 mfc_source = {sizeof(source) , AF_INET6 };
885 static struct sockaddr_in6 group = {sizeof(group) , AF_INET6 };
887 static struct sockaddr_in6 rp_addr = {sizeof(source) , AF_INET6 };
889 mrtentry_t *mrtentry_ptr;
890 mrtentry_t *mrtentry_rp;
893 * When there is a cache miss, we check only the header of the packet
894 * (and only it should be sent up by the kernel.)
896 group.sin6_addr = im->im6_dst;
897 group.sin6_scope_id = inet6_uvif2scopeid(&group, &uvifs[im->im6_mif]);
898 source.sin6_addr = mfc_source.sin6_addr = im->im6_src;
899 source.sin6_scope_id = inet6_uvif2scopeid(&source, &uvifs[im->im6_mif]);
902 uvifs[iif].uv_cache_miss++;
904 log(LOG_DEBUG, 0, "Cache miss, src %s, dst %s, iif %d",
905 inet6_fmt(&source.sin6_addr), inet6_fmt(&group.sin6_addr), iif);
908 * TODO: XXX: check whether the kernel generates cache miss for the LAN
912 /* Don't create routing entries for the LAN scoped addresses */
914 if (IN6_IS_ADDR_MC_NODELOCAL(&group.sin6_addr) ||/* sanity? */
915 IN6_IS_ADDR_MC_LINKLOCAL(&group.sin6_addr))
918 /* TODO: check if correct in case the source is one of my addresses */
920 * If I am the DR for this source, create (S,G) and add the register_vif
923 if ((uvifs[iif].uv_flags & VIFF_DR)
924 && (find_vif_direct_local(&source) == iif))
926 mrtentry_ptr = find_route(&source, &group, MRTF_SG, CREATE);
927 if (mrtentry_ptr == (mrtentry_t *) NULL)
932 mrtentry_ptr->flags &= ~MRTF_NEW;
934 /* set reg_vif_num as outgoing interface ONLY if I am not the RP */
936 if (!inet6_equal(&mrtentry_ptr->group->rpaddr, &my_cand_rp_address))
937 IF_SET(reg_vif_num, &mrtentry_ptr->joined_oifs);
938 change_interfaces(mrtentry_ptr,
939 mrtentry_ptr->incoming,
940 &mrtentry_ptr->joined_oifs,
941 &mrtentry_ptr->pruned_oifs,
942 &mrtentry_ptr->leaves,
943 &mrtentry_ptr->asserted_oifs, 0);
947 mrtentry_ptr = find_route(&source, &group,
948 MRTF_SG | MRTF_WC | MRTF_PMBR,
950 if (mrtentry_ptr == (mrtentry_t *) NULL)
955 * TODO: if there are too many cache miss for the same (S,G), install
956 * negative cache entry in the kernel (oif==NULL) to prevent too many
959 if (mrtentry_ptr->incoming == iif)
961 if (!IF_ISEMPTY(&mrtentry_ptr->oifs))
963 if (mrtentry_ptr->flags & MRTF_SG)
965 /* TODO: check that the RPbit is not set? */
966 /* TODO: XXX: TIMER implem. dependency! */
968 if (mrtentry_ptr->timer < pim_data_timeout)
969 SET_TIMER(mrtentry_ptr->timer, pim_data_timeout);
970 if (!(mrtentry_ptr->flags & MRTF_SPT))
972 if ((mrtentry_rp = mrtentry_ptr->group->grp_route) ==
974 mrtentry_rp = mrtentry_ptr->group->active_rp_grp->rp->rpentry->mrtlink;
975 if (mrtentry_rp != (mrtentry_t *) NULL)
978 * Check if the (S,G) iif is different from the (*,G)
981 if ((mrtentry_ptr->incoming != mrtentry_rp->incoming)
982 || (mrtentry_ptr->upstream != mrtentry_rp->upstream))
984 mrtentry_ptr->flags |= MRTF_SPT;
985 mrtentry_ptr->flags &= ~MRTF_RP;
990 if (mrtentry_ptr->flags & MRTF_PMBR)
991 rp_addr = mrtentry_ptr->source->address;
993 rp_addr = mrtentry_ptr->group->rpaddr;
996 #ifdef KERNEL_MFC_WC_G
997 if (mrtentry_ptr->flags & (MRTF_WC | MRTF_PMBR))
998 if (!(mrtentry_ptr->flags & MRTF_MFC_CLONE_SG))
999 mfc_source = IN6ADDR_ANY_N;
1000 #endif /* KERNEL_MFC_WC_G */
1002 add_kernel_cache(mrtentry_ptr, &mfc_source, &group, MFC_MOVE_FORCE);
1003 k_chg_mfc(mld6_socket, &mfc_source, &group, iif, &mrtentry_ptr->oifs,
1006 * TODO: XXX: No need for RSRR message, because nothing has
1010 return; /* iif match */
1013 /* The iif doesn't match */
1014 if (mrtentry_ptr->flags & MRTF_SG)
1016 if (mrtentry_ptr->flags & MRTF_SPT)
1017 /* Arrived on wrong interface */
1019 if ((mrtentry_rp = mrtentry_ptr->group->grp_route) ==
1020 (mrtentry_t *) NULL)
1022 mrtentry_ptr->group->active_rp_grp->rp->rpentry->mrtlink;
1023 if (mrtentry_rp != (mrtentry_t *) NULL)
1025 if (mrtentry_rp->incoming == iif)
1027 /* Forward on (*,G) or (*,*,RP) */
1029 #ifdef KERNEL_MFC_WC_G
1030 if (!(mrtentry_rp->flags & MRTF_MFC_CLONE_SG))
1031 mfc_source = IN6ADDR_ANY_N;
1032 #endif /* KERNEL_MFC_WC_G */
1034 add_kernel_cache(mrtentry_rp, &mfc_source, &group, 0);
1035 k_chg_mfc(mld6_socket, &mfc_source, &group, iif,
1036 &mrtentry_rp->oifs, &mrtentry_ptr->group->rpaddr);
1038 rsrr_cache_send(mrtentry_rp, RSRR_NOTIFICATION_OK);
1048 uvifs[iif].uv_cache_notcreated++;
1053 * A multicast packet has been received on wrong iif by the kernel. Check for
1054 * a matching entry. If there is (S,G) with reset SPTbit and the packet was
1055 * received on the iif toward the source, this completes the switch to the
1056 * shortest path and triggers (S,G) prune toward the RP (unless I am the RP).
1057 * Otherwise, if the packet's iif is in the oiflist of the routing entry,
1058 * trigger an Assert.
1062 process_wrong_iif(im)
1065 static struct sockaddr_in6 source= {sizeof(source) , AF_INET6};
1066 static struct sockaddr_in6 group = {sizeof(group) , AF_INET6};
1068 mrtentry_t *mrtentry_ptr;
1070 group.sin6_addr = im->im6_dst;
1071 source.sin6_addr = im->im6_src;
1075 /* Don't create routing entries for the LAN scoped addresses */
1076 if (IN6_IS_ADDR_MC_NODELOCAL(&group.sin6_addr) ||/* sanity? */
1077 IN6_IS_ADDR_MC_LINKLOCAL(&group.sin6_addr))
1082 * Ignore if it comes on register vif. register vif is neither SPT iif,
1083 * neither is used to send asserts out.
1085 if (uvifs[iif].uv_flags & MIFF_REGISTER)
1088 mrtentry_ptr = find_route(&source, &group, MRTF_SG | MRTF_WC | MRTF_PMBR,
1090 if (mrtentry_ptr == (mrtentry_t *)NULL)
1094 * TODO: check again!
1096 if (mrtentry_ptr->flags & MRTF_SG)
1098 if (!(mrtentry_ptr->flags & MRTF_SPT))
1100 if (mrtentry_ptr->source->incoming == iif)
1102 /* Switch to the Shortest Path */
1103 mrtentry_ptr->flags |= MRTF_SPT;
1104 mrtentry_ptr->flags &= ~MRTF_RP;
1105 add_kernel_cache(mrtentry_ptr, &source, &group, MFC_MOVE_FORCE);
1106 k_chg_mfc(mld6_socket, &source, &group, iif,
1107 &mrtentry_ptr->oifs, &mrtentry_ptr->group->rpaddr);
1108 FIRE_TIMER(mrtentry_ptr->jp_timer);
1110 rsrr_cache_send(mrtentry_ptr, RSRR_NOTIFICATION_OK);
1117 /* Trigger an Assert */
1118 if (IF_ISSET(iif, &mrtentry_ptr->oifs))
1119 send_pim6_assert(&source, &group, iif, mrtentry_ptr);
1123 * Receives whole packets from the register vif entries in the kernel, and
1124 * calls the send_pim_register procedure to encapsulate the packets and
1125 * unicasts them to the RP.
1128 process_whole_pkt(buf)
1132 send_pim6_register((char *) (buf + sizeof(struct mrt6msg)));
1138 switch_shortest_path(source, group)
1139 struct sockaddr_in6 *source;
1140 struct sockaddr_in6 *group;
1142 mrtentry_t *mrtentry_ptr;
1144 /* TODO: XXX: prepare and send immediately the (S,G) join? */
1145 if ((mrtentry_ptr = find_route(source, group, MRTF_SG, CREATE)) !=
1146 (mrtentry_t *) NULL)
1148 if (mrtentry_ptr->flags & MRTF_NEW)
1150 mrtentry_ptr->flags &= ~MRTF_NEW;
1154 if (mrtentry_ptr->flags & MRTF_RP)
1157 * (S,G)RPbit with iif toward RP. Reset to (S,G) with iif
1158 * toward S. Delete the kernel cache (if any), because
1159 * change_interfaces() will reset it with iif toward S and no
1160 * data will arrive from RP before the switch really occurs.
1162 mrtentry_ptr->flags &= ~MRTF_RP;
1163 mrtentry_ptr->incoming = mrtentry_ptr->source->incoming;
1164 mrtentry_ptr->upstream = mrtentry_ptr->source->upstream;
1165 delete_mrtentry_all_kernel_cache(mrtentry_ptr);
1166 change_interfaces(mrtentry_ptr,
1167 mrtentry_ptr->incoming,
1168 &mrtentry_ptr->joined_oifs,
1169 &mrtentry_ptr->pruned_oifs,
1170 &mrtentry_ptr->leaves,
1171 &mrtentry_ptr->asserted_oifs, 0);
1175 SET_TIMER(mrtentry_ptr->timer, pim_data_timeout);
1176 FIRE_TIMER(mrtentry_ptr->jp_timer);
1178 return (mrtentry_ptr);