summaryrefslogtreecommitdiffstats
path: root/usr.sbin/pim6sd/rp.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/pim6sd/rp.c')
-rw-r--r--usr.sbin/pim6sd/rp.c1210
1 files changed, 1210 insertions, 0 deletions
diff --git a/usr.sbin/pim6sd/rp.c b/usr.sbin/pim6sd/rp.c
new file mode 100644
index 0000000..48936e4
--- /dev/null
+++ b/usr.sbin/pim6sd/rp.c
@@ -0,0 +1,1210 @@
+/*
+ * Copyright (C) 1999 LSIIT Laboratory.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project nor the names of its contributors
+ * may be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+/*
+ * Copyright (c) 1998 by the University of Southern California.
+ * All rights reserved.
+ *
+ * Permission to use, copy, modify, and distribute this software and
+ * its documentation in source and binary forms for lawful
+ * purposes and without fee is hereby granted, provided
+ * that the above copyright notice appear in all copies and that both
+ * the copyright notice and this permission notice appear in supporting
+ * documentation, and that any documentation, advertising materials,
+ * and other materials related to such distribution and use acknowledge
+ * that the software was developed by the University of Southern
+ * California and/or Information Sciences Institute.
+ * The name of the University of Southern California may not
+ * be used to endorse or promote products derived from this software
+ * without specific prior written permission.
+ *
+ * THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
+ * ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
+ * PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
+ * NON-INFRINGEMENT.
+ *
+ * IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
+ * SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
+ * TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
+ * THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ *
+ * Other copyrights might apply to parts of this software and are so
+ * noted when applicable.
+ *
+ * $FreeBSD$
+ */
+/*
+ * Questions concerning this software should be directed to
+ * Mickael Hoerdt (hoerdt@clarinet.u-strasbg.fr) LSIIT Strasbourg.
+ *
+ */
+/*
+ * This program has been derived from pim6dd.
+ * The pim6dd program is covered by the license in the accompanying file
+ * named "LICENSE.pim6dd".
+ */
+/*
+ * This program has been derived from pimd.
+ * The pimd program is covered by the license in the accompanying file
+ * named "LICENSE.pimd".
+ *
+ */
+
+#include <stdlib.h>
+#include <syslog.h>
+#include "rp.h"
+#include "pim6_proto.h"
+#include "pimd.h"
+#include <netinet6/pim6.h>
+#include "timer.h"
+#include "inet6.h"
+#include "route.h"
+#include "pimd.h"
+#include "debug.h"
+#include "crc.h"
+
+/*
+ * The hash function. Stollen from Eddy's (eddy@isi.edu) implementation (for
+ * compatibility ;)
+ */
+
+#define SEED1 1103515245
+#define SEED2 12345
+#define RP_HASH_VALUE(G, M, C) (((SEED1) * (((SEED1) * ((G) & (M)) + (SEED2)) ^ (C)) + (SEED2)) % 0x80000000)
+#define RP_HASH_VALUE2(P, C) (((SEED1) * (((SEED1) * (P) + (SEED2)) ^ (C)) + (SEED2)) % 0x80000000)
+
+cand_rp_t *cand_rp_list;
+grp_mask_t *grp_mask_list;
+cand_rp_t *segmented_cand_rp_list;
+grp_mask_t *segmented_grp_mask_list;
+u_int16 curr_bsr_fragment_tag;
+u_int8 curr_bsr_priority;
+struct sockaddr_in6 curr_bsr_address;
+struct in6_addr curr_bsr_hash_mask;
+u_int16 pim_bootstrap_timer; /* For electing the BSR and sending
+ * Cand-RP-set msgs */
+u_int8 my_bsr_priority;
+struct sockaddr_in6 my_bsr_address;
+struct in6_addr my_bsr_hash_mask;
+u_int8 cand_bsr_flag = FALSE; /* Set to TRUE if I am a candidate
+ * BSR */
+struct sockaddr_in6 my_cand_rp_address;
+u_int8 my_cand_rp_priority;
+u_int16 my_cand_rp_holdtime;
+u_int16 my_cand_rp_adv_period; /* The locally configured Cand-RP
+ * adv. period. */
+u_int16 my_bsr_period; /* The locally configured BSR
+ period */
+u_int16 pim_cand_rp_adv_timer;
+u_int8 cand_rp_flag = FALSE; /* Candidate RP flag */
+struct cand_rp_adv_message_ cand_rp_adv_message;
+struct in6_addr rp_my_ipv6_hashmask;
+
+
+/*
+ * Local functions definition.
+ */
+static cand_rp_t *add_cand_rp __P((cand_rp_t **used_cand_rp_list ,
+ struct sockaddr_in6 *address));
+
+static grp_mask_t *add_grp_mask __P((grp_mask_t ** used_grp_mask_list,
+ struct sockaddr_in6 *group_addr,
+ struct in6_addr group_mask,
+ struct in6_addr hash_mask));
+
+static void delete_grp_mask_entry __P((cand_rp_t ** used_cand_rp_list,
+ grp_mask_t ** used_grp_mask_list,
+ grp_mask_t * grp_mask_delete));
+
+static void delete_rp_entry __P((cand_rp_t ** used_cand_rp_list,
+ grp_mask_t ** used_grp_mask_list,
+ cand_rp_t * cand_rp_ptr));
+
+
+void
+init_rp6_and_bsr6()
+{
+ /* TODO: if the grplist is not NULL, remap all groups ASAP! */
+
+ delete_rp_list(&cand_rp_list, &grp_mask_list);
+ delete_rp_list(&segmented_cand_rp_list, &segmented_grp_mask_list);
+
+ if (cand_bsr_flag == FALSE)
+ {
+ /*
+ * If I am not candidat BSR, initialize the "current BSR" as having
+ * the lowest priority.
+ */
+
+ curr_bsr_fragment_tag = 0;
+ curr_bsr_priority = 0; /* Lowest priority */
+ curr_bsr_address = sockaddr6_any; /* Lowest priority */
+ MASKLEN_TO_MASK6(RP_DEFAULT_IPV6_HASHMASKLEN, curr_bsr_hash_mask);
+ SET_TIMER(pim_bootstrap_timer, PIM_BOOTSTRAP_TIMEOUT);
+ }
+ else
+ {
+ curr_bsr_fragment_tag = RANDOM();
+ curr_bsr_priority = my_bsr_priority;
+ curr_bsr_address = my_bsr_address;
+ curr_bsr_hash_mask = my_bsr_hash_mask;
+ SET_TIMER(pim_bootstrap_timer, bootstrap_initial_delay());
+ }
+
+ if (cand_rp_flag != FALSE)
+ {
+ MASKLEN_TO_MASK6(RP_DEFAULT_IPV6_HASHMASKLEN, rp_my_ipv6_hashmask);
+ /* Setup the Cand-RP-Adv-Timer */
+ SET_TIMER(pim_cand_rp_adv_timer, RANDOM() % my_cand_rp_adv_period);
+ }
+}
+
+
+/*
+ * XXX: This implementation is based on section 6.2 of RFC 2362, which
+ * is highly dependent on IPv4.
+ * We'll have to rewrite the function...
+ */
+u_int16
+bootstrap_initial_delay()
+{
+// long AddrDelay;
+// long Delay;
+// long log_mask;
+// int log_of_2;
+// u_int8 bestPriority;
+
+ /*
+ * The bootstrap timer initial value (if Cand-BSR). It depends of the
+ * bootstrap router priority: higher priority has shorter value:
+ *
+ * Delay = 5 + 2*log_2(1 + bestPriority - myPriority) + AddrDelay;
+ *
+ * bestPriority = Max(storedPriority, myPriority); if (bestPriority ==
+ * myPriority) AddrDelay = log_2(bestAddr - myAddr)/16; else AddrDelay =
+ * 2 - (myAddr/2^31);
+ */
+
+// bestPriority = max(curr_bsr_priority, my_bsr_priority);
+// if (bestPriority == my_bsr_priority)
+ // {
+// AddrDelay = ntohl(curr_bsr_address) - ntohl(my_bsr_address);
+ /* Calculate the integer part of log_2 of (bestAddr - myAddr) */
+ /*
+ * To do so, have to find the position number of the first bit from
+ * left which is `1`
+ */
+// log_mask = sizeof(AddrDelay) << 3;
+// log_mask = (1 << (log_mask - 1)); /* Set the leftmost bit to
+// * `1` */
+/* for (log_of_2 = (sizeof(AddrDelay) << 3) - 1; log_of_2; log_of_2--)
+ {
+ if (AddrDelay & log_mask)
+ break;
+ else
+*/
+// log_mask >>= 1; /* Start shifting `1` on right */
+/* }
+ AddrDelay = log_of_2 / 16;
+ }
+ else
+ AddrDelay = 2 - (ntohl(my_bsr_address) / (1 << 31));
+
+ Delay = 1 + bestPriority - my_bsr_priority;
+ */
+ /* Calculate log_2(Delay) */
+// log_mask = sizeof(Delay) << 3;
+// log_mask = (1 << (log_mask - 1));
+/* Set the leftmost bit to `1`
+*/
+
+ /* for (log_of_2 = (sizeof(Delay) << 3) - 1; log_of_2; log_of_2--)
+ {
+ if (Delay & log_mask)
+ break;
+ else
+*/
+// log_mask >>= 1; /* Start shifting `1` on right */
+
+/* }
+
+ Delay = 5 + 2 * Delay + AddrDelay;
+ return (u_int16) Delay;
+*/
+
+ /* Temporary implementation */
+ return (RANDOM()%my_bsr_period);
+}
+
+
+static cand_rp_t *
+add_cand_rp(used_cand_rp_list, address)
+ cand_rp_t **used_cand_rp_list;
+ struct sockaddr_in6 *address;
+{
+ cand_rp_t *cand_rp_prev = (cand_rp_t *) NULL;
+ cand_rp_t *cand_rp;
+ cand_rp_t *cand_rp_new;
+ rpentry_t *rpentry_ptr;
+
+ /* The ordering is the bigger first */
+ for (cand_rp = *used_cand_rp_list; cand_rp != (cand_rp_t *) NULL;
+ cand_rp_prev = cand_rp, cand_rp = cand_rp->next)
+ {
+
+ if (inet6_greaterthan(&cand_rp->rpentry->address, address))
+ continue;
+ if (inet6_equal(&cand_rp->rpentry->address , address))
+ return (cand_rp);
+ else
+ break;
+ }
+
+ /* Create and insert the new entry between cand_rp_prev and cand_rp */
+ cand_rp_new = (cand_rp_t *) malloc(sizeof(cand_rp_t));
+ cand_rp_new->rp_grp_next = (rp_grp_entry_t *) NULL;
+ cand_rp_new->next = cand_rp;
+ cand_rp_new->prev = cand_rp_prev;
+ if (cand_rp != (cand_rp_t *) NULL)
+ cand_rp->prev = cand_rp_new;
+ if (cand_rp_prev == (cand_rp_t *) NULL)
+ {
+ *used_cand_rp_list = cand_rp_new;
+ }
+ else
+ {
+ cand_rp_prev->next = cand_rp_new;
+ }
+
+ rpentry_ptr = (rpentry_t *) malloc(sizeof(rpentry_t));
+ cand_rp_new->rpentry = rpentry_ptr;
+ rpentry_ptr->next = (srcentry_t *) NULL;
+ rpentry_ptr->prev = (srcentry_t *) NULL;
+ rpentry_ptr->address = *address;
+ rpentry_ptr->mrtlink = (mrtentry_t *) NULL;
+ rpentry_ptr->incoming = NO_VIF;
+ rpentry_ptr->upstream = (pim_nbr_entry_t *) NULL;
+
+ /* TODO: setup the metric and the preference as ~0 (the lowest)? */
+
+ rpentry_ptr->metric = ~0;
+ rpentry_ptr->preference = ~0;
+ RESET_TIMER(rpentry_ptr->timer);
+ rpentry_ptr->cand_rp = cand_rp_new;
+
+ /*
+ * TODO: XXX: check whether there is a route to that RP: if return value
+ * is FALSE, then no route.
+ */
+
+ if (local_address(&rpentry_ptr->address) == NO_VIF)
+ {
+ /* TODO: check for error and delete */
+ set_incoming(rpentry_ptr, PIM_IIF_RP);
+ }
+ else
+ {
+ /* TODO: XXX: CHECK!!! */
+ rpentry_ptr->incoming = reg_vif_num;
+ }
+
+ return (cand_rp_new);
+}
+
+
+static grp_mask_t *
+add_grp_mask(used_grp_mask_list, group_addr, group_mask, hash_mask)
+ grp_mask_t **used_grp_mask_list;
+ struct sockaddr_in6 *group_addr;
+ struct in6_addr group_mask;
+ struct in6_addr hash_mask;
+{
+ grp_mask_t *grp_mask_prev = (grp_mask_t *) NULL;
+ grp_mask_t *grp_mask;
+ grp_mask_t *grp_mask_tmp;
+ struct sockaddr_in6 prefix_h;
+ struct sockaddr_in6 prefix_h2;
+ int i;
+
+ /* I compare on the adresses, inet6_equal use the scope, too */
+ prefix_h.sin6_scope_id = prefix_h2.sin6_scope_id = 0;
+
+ for (i = 0; i < sizeof(struct in6_addr); i++)
+ prefix_h.sin6_addr.s6_addr[i] =
+ group_addr->sin6_addr.s6_addr[i] & group_mask.s6_addr[i];
+
+ /* The ordering is: smaller first */
+ for (grp_mask = *used_grp_mask_list; grp_mask != (grp_mask_t *) NULL;
+ grp_mask_prev = grp_mask, grp_mask = grp_mask->next)
+ {
+ for (i = 0; i < sizeof(struct in6_addr); i++)
+ prefix_h2.sin6_addr.s6_addr[i] =
+ (grp_mask->group_addr.sin6_addr.s6_addr[i] &
+ grp_mask->group_mask.s6_addr[i]);
+ if (inet6_lessthan(&prefix_h2, &prefix_h) )
+ continue;
+ if (inet6_equal(&prefix_h2, &prefix_h))
+ return (grp_mask);
+ else
+ break;
+ }
+
+ grp_mask_tmp = (grp_mask_t *) malloc(sizeof(grp_mask_t));
+ grp_mask_tmp->grp_rp_next = (rp_grp_entry_t *) NULL;
+ grp_mask_tmp->next = grp_mask;
+ grp_mask_tmp->prev = grp_mask_prev;
+ if (grp_mask != (grp_mask_t *) NULL)
+ grp_mask->prev = grp_mask_tmp;
+ if (grp_mask_prev == (grp_mask_t *) NULL)
+ {
+ *used_grp_mask_list = grp_mask_tmp;
+ }
+ else
+ {
+ grp_mask_prev->next = grp_mask_tmp;
+ }
+
+ grp_mask_tmp->group_addr = *group_addr;
+ grp_mask_tmp->group_mask = group_mask;
+ grp_mask_tmp->hash_mask = hash_mask;
+ grp_mask_tmp->group_rp_number = 0;
+ grp_mask_tmp->fragment_tag = 0;
+ return (grp_mask_tmp);
+}
+
+
+/*
+ * TODO: XXX: BUG: a remapping for some groups currently using some other
+ * grp_mask may be required by the addition of the new entry!!! Remapping all
+ * groups might be a costly process...
+ */
+rp_grp_entry_t *
+add_rp_grp_entry(used_cand_rp_list, used_grp_mask_list,
+ rp_addr, rp_priority, rp_holdtime, group_addr, group_mask,
+ bsr_hash_mask,
+ fragment_tag)
+ cand_rp_t **used_cand_rp_list;
+ grp_mask_t **used_grp_mask_list;
+ struct sockaddr_in6 *rp_addr;
+ u_int8 rp_priority;
+ u_int16 rp_holdtime;
+ struct sockaddr_in6 *group_addr;
+ struct in6_addr group_mask;
+ struct in6_addr bsr_hash_mask;
+ u_int16 fragment_tag;
+{
+ cand_rp_t *cand_rp_ptr;
+ grp_mask_t *grp_mask_ptr;
+ rpentry_t *rpentry_ptr;
+ rp_grp_entry_t *grp_rp_entry_next;
+ rp_grp_entry_t *grp_rp_entry_new;
+ rp_grp_entry_t *grp_rp_entry_prev = (rp_grp_entry_t *) NULL;
+ grpentry_t *grpentry_ptr_prev;
+ grpentry_t *grpentry_ptr_next;
+ u_int8 old_highest_priority = ~0; /* Smaller value means
+ * "higher" */
+
+ /* Input data verification */
+ if (!inet6_valid_host(rp_addr))
+ return (rp_grp_entry_t *) NULL;
+
+ if (!IN6_IS_ADDR_MULTICAST(&group_addr->sin6_addr))
+ {
+ return (rp_grp_entry_t *) NULL;
+ }
+ grp_mask_ptr = add_grp_mask(used_grp_mask_list, group_addr, group_mask,
+ bsr_hash_mask);
+ if (grp_mask_ptr == (grp_mask_t *) NULL)
+ return (rp_grp_entry_t *) NULL;
+
+ /* TODO: delete */
+#if 0
+ if (grp_mask_ptr->grp_rp_next != (rp_grp_entry_t *) NULL)
+ {
+ /* Check for obsolete grp_rp chain */
+ if ((my_bsr_address != curr_bsr_address)
+ && (grp_mask_ptr->grp_rp_next->fragment_tag != fragment_tag))
+ {
+ /* This grp_rp chain is obsolete. Delete it. */
+ delete_grp_mask(used_cand_rp_list, used_grp_mask_list,
+ group_addr, group_mask);
+ grp_mask_ptr = add_grp_mask(used_grp_mask_list, group_addr,
+ group_mask, bsr_hash_mask);
+ if (grp_mask_ptr == (grp_mask_t *) NULL)
+ return (rp_grp_entry_t *) NULL;
+ }
+ }
+#endif /* 0 */
+
+ cand_rp_ptr = add_cand_rp(used_cand_rp_list, rp_addr);
+ if (cand_rp_ptr == (cand_rp_t *) NULL)
+ {
+ if (grp_mask_ptr->grp_rp_next == (rp_grp_entry_t *) NULL)
+ delete_grp_mask(used_cand_rp_list, used_grp_mask_list,
+ group_addr, group_mask);
+ return (rp_grp_entry_t *) NULL;
+ }
+
+ rpentry_ptr = cand_rp_ptr->rpentry;
+ SET_TIMER(rpentry_ptr->timer, rp_holdtime);
+ grp_mask_ptr->fragment_tag = fragment_tag; /* For garbage collection */
+
+ grp_rp_entry_prev = (rp_grp_entry_t *) NULL;
+ grp_rp_entry_next = grp_mask_ptr->grp_rp_next;
+
+ /* TODO: improve it */
+
+ if (grp_rp_entry_next != (rp_grp_entry_t *) NULL)
+ old_highest_priority = grp_rp_entry_next->priority;
+ for (; grp_rp_entry_next != (rp_grp_entry_t *) NULL;
+ grp_rp_entry_prev = grp_rp_entry_next,
+ grp_rp_entry_next = grp_rp_entry_next->grp_rp_next)
+ {
+ /*
+ * Smaller value means higher priority. The entries are sorted with
+ * the highest priority first.
+ */
+ if (grp_rp_entry_next->priority < rp_priority)
+ continue;
+ if (grp_rp_entry_next->priority > rp_priority)
+ break;
+
+ /*
+ * Here we don't care about higher/lower addresses, because higher
+ * address does not guarantee higher hash_value, but anyway we do
+ * order with the higher address first, so it will be easier to find
+ * an existing entry and update the holdtime.
+ */
+
+ if (inet6_greaterthan(&grp_rp_entry_next->rp->rpentry->address , rp_addr))
+ continue;
+ if (inet6_lessthan(&grp_rp_entry_next->rp->rpentry->address , rp_addr))
+ break;
+
+ /* We already have this entry. Update the holdtime */
+ /*
+ * TODO: We shoudn't have old existing entry, because with the
+ * current implementation all of them will be deleted (different
+ * fragment_tag). Debug and check and eventually delete.
+ */
+
+ grp_rp_entry_next->holdtime = rp_holdtime;
+ grp_rp_entry_next->advholdtime = rp_holdtime;
+ grp_rp_entry_next->fragment_tag = fragment_tag;
+ return (grp_rp_entry_next);
+ }
+
+ /* Create and link the new entry */
+
+ grp_rp_entry_new = (rp_grp_entry_t *) malloc(sizeof(rp_grp_entry_t));
+ grp_rp_entry_new->grp_rp_next = grp_rp_entry_next;
+ grp_rp_entry_new->grp_rp_prev = grp_rp_entry_prev;
+ if (grp_rp_entry_next != (rp_grp_entry_t *) NULL)
+ grp_rp_entry_next->grp_rp_prev = grp_rp_entry_new;
+ if (grp_rp_entry_prev == (rp_grp_entry_t *) NULL)
+ grp_mask_ptr->grp_rp_next = grp_rp_entry_new;
+ else
+ grp_rp_entry_prev->grp_rp_next = grp_rp_entry_new;
+
+ /*
+ * The rp_grp_entry chain is not ordered, so just plug the new entry at
+ * the head.
+ */
+
+ grp_rp_entry_new->rp_grp_next = cand_rp_ptr->rp_grp_next;
+ if (cand_rp_ptr->rp_grp_next != (rp_grp_entry_t *) NULL)
+ cand_rp_ptr->rp_grp_next->rp_grp_prev = grp_rp_entry_new;
+ grp_rp_entry_new->rp_grp_prev = (rp_grp_entry_t *) NULL;
+ cand_rp_ptr->rp_grp_next = grp_rp_entry_new;
+
+ grp_rp_entry_new->holdtime = rp_holdtime;
+ grp_rp_entry_new->advholdtime = rp_holdtime;
+ grp_rp_entry_new->fragment_tag = fragment_tag;
+ grp_rp_entry_new->priority = rp_priority;
+ grp_rp_entry_new->group = grp_mask_ptr;
+ grp_rp_entry_new->rp = cand_rp_ptr;
+ grp_rp_entry_new->grplink = (grpentry_t *) NULL;
+
+ grp_mask_ptr->group_rp_number++;
+
+ if (grp_mask_ptr->grp_rp_next->priority == rp_priority)
+ {
+ /* The first entries are with the best priority. */
+ /* Adding this rp_grp_entry may result in group_to_rp remapping */
+ for (grp_rp_entry_next = grp_mask_ptr->grp_rp_next;
+ grp_rp_entry_next != (rp_grp_entry_t *) NULL;
+ grp_rp_entry_next = grp_rp_entry_next->grp_rp_next)
+ {
+ if (grp_rp_entry_next->priority > old_highest_priority)
+ break;
+ for (grpentry_ptr_prev = grp_rp_entry_next->grplink;
+ grpentry_ptr_prev != (grpentry_t *) NULL;)
+ {
+ grpentry_ptr_next = grpentry_ptr_prev->rpnext;
+ remap_grpentry(grpentry_ptr_prev);
+ grpentry_ptr_prev = grpentry_ptr_next;
+ }
+ }
+ }
+
+ return (grp_rp_entry_new);
+}
+
+
+void
+delete_rp_grp_entry(used_cand_rp_list, used_grp_mask_list,
+ rp_grp_entry_delete)
+ cand_rp_t **used_cand_rp_list;
+ grp_mask_t **used_grp_mask_list;
+ rp_grp_entry_t *rp_grp_entry_delete;
+{
+ grpentry_t *grpentry_ptr;
+ grpentry_t *grpentry_ptr_next;
+
+ if (rp_grp_entry_delete == (rp_grp_entry_t *) NULL)
+ return;
+ rp_grp_entry_delete->group->group_rp_number--;
+ /* Free the rp_grp* and grp_rp* links */
+ if (rp_grp_entry_delete->rp_grp_prev != (rp_grp_entry_t *) NULL)
+ rp_grp_entry_delete->rp_grp_prev->rp_grp_next =
+ rp_grp_entry_delete->rp_grp_next;
+ else
+ rp_grp_entry_delete->rp->rp_grp_next =
+ rp_grp_entry_delete->rp_grp_next;
+ if (rp_grp_entry_delete->rp_grp_next != (rp_grp_entry_t *) NULL)
+ rp_grp_entry_delete->rp_grp_next->rp_grp_prev =
+ rp_grp_entry_delete->rp_grp_prev;
+
+ if (rp_grp_entry_delete->grp_rp_prev != (rp_grp_entry_t *) NULL)
+ rp_grp_entry_delete->grp_rp_prev->grp_rp_next =
+ rp_grp_entry_delete->grp_rp_next;
+ else
+ rp_grp_entry_delete->group->grp_rp_next =
+ rp_grp_entry_delete->grp_rp_next;
+ if (rp_grp_entry_delete->grp_rp_next != (rp_grp_entry_t *) NULL)
+ rp_grp_entry_delete->grp_rp_next->grp_rp_prev =
+ rp_grp_entry_delete->grp_rp_prev;
+
+ /* Delete Cand-RP or Group-prefix if useless */
+ if (rp_grp_entry_delete->group->grp_rp_next ==
+ (rp_grp_entry_t *) NULL)
+ delete_grp_mask_entry(used_cand_rp_list, used_grp_mask_list,
+ rp_grp_entry_delete->group);
+ if (rp_grp_entry_delete->rp->rp_grp_next ==
+ (rp_grp_entry_t *) NULL)
+ delete_rp_entry(used_cand_rp_list, used_grp_mask_list,
+ rp_grp_entry_delete->rp);
+
+ /* Remap all affected groups */
+ for (grpentry_ptr = rp_grp_entry_delete->grplink;
+ grpentry_ptr != (grpentry_t *) NULL;
+ grpentry_ptr = grpentry_ptr_next)
+ {
+ grpentry_ptr_next = grpentry_ptr->rpnext;
+ remap_grpentry(grpentry_ptr);
+ }
+
+ free((char *) rp_grp_entry_delete);
+}
+
+/*
+ * TODO: XXX: the affected group entries will be partially setup, because may
+ * have group routing entry, but NULL pointers to RP. After the call to this
+ * function, must remap all group entries ASAP.
+ */
+
+void
+delete_rp_list(used_cand_rp_list, used_grp_mask_list)
+ cand_rp_t **used_cand_rp_list;
+ grp_mask_t **used_grp_mask_list;
+{
+ cand_rp_t *cand_rp_ptr,
+ *cand_rp_next;
+ grp_mask_t *grp_mask_ptr,
+ *grp_mask_next;
+ rp_grp_entry_t *rp_grp_entry_ptr,
+ *rp_grp_entry_next;
+ grpentry_t *grpentry_ptr,
+ *grpentry_ptr_next;
+
+ for (cand_rp_ptr = *used_cand_rp_list;
+ cand_rp_ptr != (cand_rp_t *) NULL;)
+ {
+ cand_rp_next = cand_rp_ptr->next;
+ /* Free the mrtentry (if any) for this RP */
+ if (cand_rp_ptr->rpentry->mrtlink != (mrtentry_t *) NULL)
+ {
+ if (cand_rp_ptr->rpentry->mrtlink->flags & MRTF_KERNEL_CACHE)
+ delete_mrtentry_all_kernel_cache(cand_rp_ptr->rpentry->mrtlink);
+ FREE_MRTENTRY(cand_rp_ptr->rpentry->mrtlink);
+ }
+ free(cand_rp_ptr->rpentry);
+
+ /* Free the whole chain of rp_grp_entry for this RP */
+ for (rp_grp_entry_ptr = cand_rp_ptr->rp_grp_next;
+ rp_grp_entry_ptr != (rp_grp_entry_t *) NULL;
+ rp_grp_entry_ptr = rp_grp_entry_next)
+ {
+ rp_grp_entry_next = rp_grp_entry_ptr->rp_grp_next;
+ /* Clear the RP related invalid pointers for all group entries */
+ for (grpentry_ptr = rp_grp_entry_ptr->grplink;
+ grpentry_ptr != (grpentry_t *) NULL;
+ grpentry_ptr = grpentry_ptr_next)
+ {
+ grpentry_ptr_next = grpentry_ptr->rpnext;
+ grpentry_ptr->rpnext = (grpentry_t *) NULL;
+ grpentry_ptr->rpprev = (grpentry_t *) NULL;
+ grpentry_ptr->active_rp_grp = (rp_grp_entry_t *) NULL;
+ grpentry_ptr->rpaddr = sockaddr6_any;
+ }
+ free(rp_grp_entry_ptr);
+ }
+ cand_rp_ptr = cand_rp_next;
+ }
+ *used_cand_rp_list = (cand_rp_t *) NULL;
+
+ for (grp_mask_ptr = *used_grp_mask_list;
+ grp_mask_ptr != (grp_mask_t *) NULL;
+ grp_mask_ptr = grp_mask_next)
+ {
+ grp_mask_next = grp_mask_ptr->next;
+ free(grp_mask_ptr);
+ }
+ *used_grp_mask_list = (grp_mask_t *) NULL;
+}
+
+
+void
+delete_grp_mask(used_cand_rp_list, used_grp_mask_list, group_addr, group_mask)
+ cand_rp_t **used_cand_rp_list;
+ grp_mask_t **used_grp_mask_list;
+ struct sockaddr_in6 *group_addr;
+ struct in6_addr group_mask;
+{
+ grp_mask_t *grp_mask_ptr;
+ struct sockaddr_in6 prefix_h;
+ struct sockaddr_in6 prefix_h2;
+ int i;
+
+ for (i = 0; i < sizeof(struct in6_addr); i++)
+ prefix_h.sin6_addr.s6_addr[i] = group_addr->sin6_addr.s6_addr[i]&group_mask.s6_addr[i];
+
+ for (grp_mask_ptr = *used_grp_mask_list;
+ grp_mask_ptr != (grp_mask_t *) NULL;
+ grp_mask_ptr = grp_mask_ptr->next)
+ {
+ for (i = 0; i < sizeof(struct in6_addr); i++)
+ prefix_h2.sin6_addr.s6_addr[i] =
+ grp_mask_ptr->group_addr.sin6_addr.s6_addr[i]&grp_mask_ptr->group_mask.s6_addr[i];
+
+ if (inet6_lessthan(&prefix_h2, &prefix_h))
+ continue;
+ if (IN6_ARE_ADDR_EQUAL(&grp_mask_ptr->group_addr.sin6_addr,
+ &group_addr->sin6_addr) &&
+ IN6_ARE_ADDR_EQUAL(&grp_mask_ptr->group_mask, &group_mask))
+ break;
+ else
+ return; /* Not found */
+ }
+
+ if (grp_mask_ptr == (grp_mask_t *) NULL)
+ return; /* Not found */
+
+ delete_grp_mask_entry(used_cand_rp_list, used_grp_mask_list,
+ grp_mask_ptr);
+}
+
+static void
+delete_grp_mask_entry(used_cand_rp_list, used_grp_mask_list, grp_mask_delete)
+ cand_rp_t **used_cand_rp_list;
+ grp_mask_t **used_grp_mask_list;
+ grp_mask_t *grp_mask_delete;
+{
+ grpentry_t *grpentry_ptr,
+ *grpentry_ptr_next;
+ rp_grp_entry_t *grp_rp_entry_ptr;
+ rp_grp_entry_t *grp_rp_entry_next;
+
+ if (grp_mask_delete == (grp_mask_t *) NULL)
+ return;
+
+ /* Remove from the grp_mask_list first */
+
+ if (grp_mask_delete->prev != (grp_mask_t *) NULL)
+ grp_mask_delete->prev->next = grp_mask_delete->next;
+ else
+ *used_grp_mask_list = grp_mask_delete->next;
+
+ if (grp_mask_delete->next != (grp_mask_t *) NULL)
+ grp_mask_delete->next->prev = grp_mask_delete->prev;
+
+ /* Remove all grp_rp entries for this grp_mask */
+ for (grp_rp_entry_ptr = grp_mask_delete->grp_rp_next;
+ grp_rp_entry_ptr != (rp_grp_entry_t *) NULL;
+ grp_rp_entry_ptr = grp_rp_entry_next)
+ {
+ grp_rp_entry_next = grp_rp_entry_ptr->grp_rp_next;
+ /* Remap all related grpentry */
+ for (grpentry_ptr = grp_rp_entry_ptr->grplink;
+ grpentry_ptr != (grpentry_t *) NULL;
+ grpentry_ptr = grpentry_ptr_next)
+ {
+ grpentry_ptr_next = grpentry_ptr->rpnext;
+ remap_grpentry(grpentry_ptr);
+
+ }
+ if (grp_rp_entry_ptr->rp_grp_prev != (rp_grp_entry_t *) NULL)
+ {
+ grp_rp_entry_ptr->rp_grp_prev->rp_grp_next =
+ grp_rp_entry_ptr->rp_grp_next;
+ }
+ else
+ {
+ grp_rp_entry_ptr->rp->rp_grp_next = grp_rp_entry_ptr->rp_grp_next;
+ }
+ if (grp_rp_entry_ptr->rp_grp_next != (rp_grp_entry_t *) NULL)
+ grp_rp_entry_ptr->rp_grp_next->rp_grp_prev =
+ grp_rp_entry_ptr->rp_grp_prev;
+ if (grp_rp_entry_ptr->rp->rp_grp_next == (rp_grp_entry_t *) NULL)
+ {
+ /* Delete the RP entry */
+ delete_rp_entry(used_cand_rp_list, used_grp_mask_list,
+ grp_rp_entry_ptr->rp);
+ }
+ free(grp_rp_entry_ptr);
+ }
+}
+
+/*
+ * TODO: currently not used.
+ */
+
+void
+delete_rp(used_cand_rp_list, used_grp_mask_list, rp_addr)
+ cand_rp_t **used_cand_rp_list;
+ grp_mask_t **used_grp_mask_list;
+ struct sockaddr_in6 *rp_addr;
+{
+ cand_rp_t *cand_rp_ptr;
+
+ for (cand_rp_ptr = *used_cand_rp_list;
+ cand_rp_ptr != (cand_rp_t *) NULL;
+ cand_rp_ptr = cand_rp_ptr->next)
+ {
+ if (inet6_greaterthan(&cand_rp_ptr->rpentry->address, rp_addr))
+ continue;
+ if (inet6_equal(&cand_rp_ptr->rpentry->address,rp_addr))
+ break;
+ else
+ return; /* Not found */
+ }
+
+ if (cand_rp_ptr == (cand_rp_t *) NULL)
+ return; /* Not found */
+ delete_rp_entry(used_cand_rp_list, used_grp_mask_list, cand_rp_ptr);
+}
+
+
+static void
+delete_rp_entry(used_cand_rp_list, used_grp_mask_list, cand_rp_delete)
+ cand_rp_t **used_cand_rp_list;
+ grp_mask_t **used_grp_mask_list;
+ cand_rp_t *cand_rp_delete;
+{
+ rp_grp_entry_t *rp_grp_entry_ptr;
+ rp_grp_entry_t *rp_grp_entry_next;
+ grpentry_t *grpentry_ptr;
+ grpentry_t *grpentry_ptr_next;
+
+ if (cand_rp_delete == (cand_rp_t *) NULL)
+ return;
+
+ /* Remove from the cand-RP chain */
+ if (cand_rp_delete->prev != (cand_rp_t *) NULL)
+ cand_rp_delete->prev->next = cand_rp_delete->next;
+ else
+ *used_cand_rp_list = cand_rp_delete->next;
+
+ if (cand_rp_delete->next != (cand_rp_t *) NULL)
+ cand_rp_delete->next->prev = cand_rp_delete->prev;
+
+ if (cand_rp_delete->rpentry->mrtlink != (mrtentry_t *) NULL)
+ {
+ if (cand_rp_delete->rpentry->mrtlink->flags & MRTF_KERNEL_CACHE)
+ delete_mrtentry_all_kernel_cache(cand_rp_delete->rpentry->mrtlink);
+ FREE_MRTENTRY(cand_rp_delete->rpentry->mrtlink);
+ }
+ free((char *) cand_rp_delete->rpentry);
+
+ /* Remove all rp_grp entries for this RP */
+ for (rp_grp_entry_ptr = cand_rp_delete->rp_grp_next;
+ rp_grp_entry_ptr != (rp_grp_entry_t *) NULL;
+ rp_grp_entry_ptr = rp_grp_entry_next)
+ {
+ rp_grp_entry_next = rp_grp_entry_ptr->rp_grp_next;
+ rp_grp_entry_ptr->group->group_rp_number--;
+
+ /* First take care of the grp_rp chain */
+ if (rp_grp_entry_ptr->grp_rp_prev != (rp_grp_entry_t *) NULL)
+ {
+ rp_grp_entry_ptr->grp_rp_prev->grp_rp_next =
+ rp_grp_entry_ptr->grp_rp_next;
+ }
+ else
+ {
+ rp_grp_entry_ptr->group->grp_rp_next =
+ rp_grp_entry_ptr->grp_rp_next;
+ }
+ if (rp_grp_entry_ptr->grp_rp_next != (rp_grp_entry_t *) NULL)
+ {
+ rp_grp_entry_ptr->grp_rp_next->grp_rp_prev =
+ rp_grp_entry_ptr->grp_rp_prev;
+ }
+
+ if (rp_grp_entry_ptr->grp_rp_next == (rp_grp_entry_t *) NULL)
+ {
+ delete_grp_mask_entry(used_cand_rp_list, used_grp_mask_list,
+ rp_grp_entry_ptr->group);
+ }
+
+ /* Remap the related groups */
+ for (grpentry_ptr = rp_grp_entry_ptr->grplink;
+ grpentry_ptr != (grpentry_t *) NULL;
+ grpentry_ptr = grpentry_ptr_next)
+ {
+ grpentry_ptr_next = grpentry_ptr->rpnext;
+ remap_grpentry(grpentry_ptr);
+ }
+ free(rp_grp_entry_ptr);
+ }
+ free((char *) cand_rp_delete);
+}
+
+
+/*
+ * Rehash the RP for the group. XXX: currently, every time when
+ * remap_grpentry() is called, there has being a good reason to change the
+ * RP, so for performancy reasons no check is performed whether the RP will
+ * be really different one.
+ */
+
+int
+remap_grpentry(grpentry_ptr)
+ grpentry_t *grpentry_ptr;
+{
+ rpentry_t *rpentry_ptr;
+ rp_grp_entry_t *rp_grp_entry_ptr;
+ mrtentry_t *grp_route;
+ mrtentry_t *mrtentry_ptr;
+
+ if (grpentry_ptr == (grpentry_t *) NULL)
+ return (FALSE);
+
+ /* Remove from the list of all groups matching to the same RP */
+ if (grpentry_ptr->rpprev != (grpentry_t *) NULL)
+ grpentry_ptr->rpprev->rpnext = grpentry_ptr->rpnext;
+ else
+ {
+ if (grpentry_ptr->active_rp_grp != (rp_grp_entry_t *) NULL)
+ grpentry_ptr->active_rp_grp->grplink = grpentry_ptr->rpnext;
+ }
+ if (grpentry_ptr->rpnext != (grpentry_t *) NULL)
+ grpentry_ptr->rpnext->rpprev = grpentry_ptr->rpprev;
+
+ rp_grp_entry_ptr = rp_grp_match(&grpentry_ptr->group);
+ if (rp_grp_entry_ptr == (rp_grp_entry_t *) NULL)
+ {
+ /* If cannot remap, delete the group */
+ delete_grpentry(grpentry_ptr);
+ return (FALSE);
+ }
+ rpentry_ptr = rp_grp_entry_ptr->rp->rpentry;
+
+ /* Add to the new chain of all groups mapping to the same RP */
+ grpentry_ptr->rpaddr = rpentry_ptr->address;
+ grpentry_ptr->active_rp_grp = rp_grp_entry_ptr;
+ grpentry_ptr->rpnext = rp_grp_entry_ptr->grplink;
+ if (grpentry_ptr->rpnext != (grpentry_t *) NULL)
+ grpentry_ptr->rpnext->rpprev = grpentry_ptr;
+ grpentry_ptr->rpprev = (grpentry_t *) NULL;
+ rp_grp_entry_ptr->grplink = grpentry_ptr;
+
+ if ((grp_route = grpentry_ptr->grp_route) != (mrtentry_t *) NULL)
+ {
+ grp_route->upstream = rpentry_ptr->upstream;
+ grp_route->metric = rpentry_ptr->metric;
+ grp_route->preference = rpentry_ptr->preference;
+ change_interfaces(grp_route, rpentry_ptr->incoming,
+ &grp_route->joined_oifs,
+ &grp_route->pruned_oifs,
+ &grp_route->leaves,
+ &grp_route->asserted_oifs, MFC_UPDATE_FORCE);
+ }
+
+ for (mrtentry_ptr = grpentry_ptr->mrtlink;
+ mrtentry_ptr != (mrtentry_t *) NULL;
+ mrtentry_ptr = mrtentry_ptr->grpnext)
+ {
+ if (!(mrtentry_ptr->flags & MRTF_RP))
+ continue;
+ mrtentry_ptr->upstream = rpentry_ptr->upstream;
+ mrtentry_ptr->metric = rpentry_ptr->metric;
+ mrtentry_ptr->preference = rpentry_ptr->preference;
+ change_interfaces(mrtentry_ptr, rpentry_ptr->incoming,
+ &mrtentry_ptr->joined_oifs,
+ &mrtentry_ptr->pruned_oifs,
+ &mrtentry_ptr->leaves,
+ &mrtentry_ptr->asserted_oifs, MFC_UPDATE_FORCE);
+ }
+
+ return (TRUE);
+}
+
+
+rpentry_t *
+rp_match(group)
+ struct sockaddr_in6 *group;
+{
+ rp_grp_entry_t *rp_grp_entry_ptr;
+
+ rp_grp_entry_ptr = rp_grp_match(group);
+ if (rp_grp_entry_ptr != (rp_grp_entry_t *) NULL)
+ return (rp_grp_entry_ptr->rp->rpentry);
+ else
+ return (rpentry_t *) NULL;
+}
+
+
+rp_grp_entry_t *
+rp_grp_match(group)
+ struct sockaddr_in6 *group;
+{
+ grp_mask_t *grp_mask_ptr;
+ rp_grp_entry_t *grp_rp_entry_ptr;
+ rp_grp_entry_t *best_entry = (rp_grp_entry_t *) NULL;
+ u_int8 best_priority = ~0; /* Smaller is better */
+ u_int32 best_hash_value = 0; /* Bigger is better */
+ struct sockaddr_in6 best_address_h; /* Bigger is better */
+ u_int32 curr_hash_value = 0;
+ struct sockaddr_in6 curr_address_h;
+
+ struct sockaddr_in6 prefix_h;
+ struct sockaddr_in6 prefix_h2;
+ int i;
+
+ if (grp_mask_list == (grp_mask_t *) NULL)
+ return (rp_grp_entry_t *) NULL;
+
+ /* XXX :I compare on the adresses , inet6_equal use the scope too */
+ prefix_h.sin6_scope_id = prefix_h2.sin6_scope_id = 0;
+
+ for (grp_mask_ptr = grp_mask_list; grp_mask_ptr != (grp_mask_t *) NULL;
+ grp_mask_ptr = grp_mask_ptr->next)
+ {
+ for (i = 0; i < sizeof(struct in6_addr); i++)
+ prefix_h2.sin6_addr.s6_addr[i] =
+ (grp_mask_ptr->group_addr.sin6_addr.s6_addr[i] &
+ grp_mask_ptr->group_mask.s6_addr[i]);
+ for (i = 0; i < sizeof(struct in6_addr); i++)
+ prefix_h.sin6_addr.s6_addr[i] =
+ (group->sin6_addr.s6_addr[i] &
+ grp_mask_ptr->group_mask.s6_addr[i]);
+
+ /* Search the grp_mask (group_prefix) list */
+ if ((inet6_greaterthan(&prefix_h, &prefix_h2)))
+ continue;
+ if ((inet6_lessthan(&prefix_h, &prefix_h2)))
+ break;
+
+ for (grp_rp_entry_ptr = grp_mask_ptr->grp_rp_next;
+ grp_rp_entry_ptr != (rp_grp_entry_t *) NULL;
+ grp_rp_entry_ptr = grp_rp_entry_ptr->grp_rp_next)
+ {
+
+ if (best_priority < grp_rp_entry_ptr->priority)
+ break;
+
+ curr_address_h = grp_rp_entry_ptr->rp->rpentry->address;
+#if 0
+ curr_hash_value = RP_HASH_VALUE(crc((char *)&group->sin6_addr,
+ sizeof(struct in6_addr)),
+ crc((char *)&grp_mask_ptr->hash_mask,
+ sizeof(struct in6_addr)),
+ crc((char *)&curr_address_h.sin6_addr,
+ sizeof(struct in6_addr)));
+#else
+ {
+ struct in6_addr masked_grp;
+ int i;
+
+ for (i = 0; i < sizeof(struct in6_addr); i++)
+ masked_grp.s6_addr[i] =
+ group->sin6_addr.s6_addr[i] &
+ grp_mask_ptr->hash_mask.s6_addr[i];
+ curr_hash_value = RP_HASH_VALUE2(crc((char *)&masked_grp,
+ sizeof(struct in6_addr)),
+ crc((char *)&curr_address_h.sin6_addr,
+ sizeof(struct in6_addr)));
+ }
+#endif
+
+ if (best_priority == grp_rp_entry_ptr->priority)
+ {
+ /* Compare the hash_value and then the addresses */
+
+ if (curr_hash_value < best_hash_value)
+ continue;
+ if (curr_hash_value == best_hash_value)
+ if (inet6_lessthan(&curr_address_h ,&best_address_h))
+ continue;
+ }
+
+ /* The current entry in the loop is preferred */
+
+ best_entry = grp_rp_entry_ptr;
+ best_priority = best_entry->priority;
+ best_address_h = curr_address_h;
+ best_hash_value = curr_hash_value;
+ }
+ }
+
+
+ if (best_entry == (rp_grp_entry_t *) NULL)
+ return (rp_grp_entry_t *) NULL;
+
+ IF_DEBUG(DEBUG_PIM_CAND_RP)
+ log(LOG_DEBUG,0,"Rp_grp_match found %s for group %s",
+ inet6_fmt(&best_entry->rp->rpentry->address.sin6_addr),
+ inet6_fmt(&group->sin6_addr));
+
+ return (best_entry);
+}
+
+
+rpentry_t *
+rp_find(rp_address)
+ struct sockaddr_in6 *rp_address;
+{
+ cand_rp_t *cand_rp_ptr;
+
+ for (cand_rp_ptr = cand_rp_list; cand_rp_ptr != (cand_rp_t *) NULL;
+ cand_rp_ptr = cand_rp_ptr->next)
+ {
+ if( inet6_greaterthan(&cand_rp_ptr->rpentry->address,rp_address))
+ continue;
+ if( inet6_equal(&cand_rp_ptr->rpentry->address,rp_address))
+ return (cand_rp_ptr->rpentry);
+ return (rpentry_t *) NULL;
+ }
+
+ return (rpentry_t *) NULL;
+}
+
+
+/*
+ * Create a bootstrap message in "send_buff" and returns the data size
+ * (excluding the IP header and the PIM header) Can be used both by the
+ * Bootstrap router to multicast the RP-set or by the DR to unicast it to a
+ * new neighbor. It DOES NOT change any timers.
+ */
+
+int
+create_pim6_bootstrap_message(send_buff)
+ char *send_buff;
+{
+ u_int8 *data_ptr;
+ grp_mask_t *grp_mask_ptr;
+ rp_grp_entry_t *grp_rp_entry_ptr;
+ int datalen;
+ u_int8 masklen=0;
+
+ if (IN6_IS_ADDR_UNSPECIFIED(&curr_bsr_address.sin6_addr))
+ return (0);
+
+ data_ptr = (u_int8 *) (send_buff + sizeof(struct pim));
+
+ if( inet6_equal(&curr_bsr_address , &my_bsr_address ))
+ curr_bsr_fragment_tag++;
+ PUT_HOSTSHORT(curr_bsr_fragment_tag, data_ptr);
+ MASK_TO_MASKLEN6(curr_bsr_hash_mask, masklen);
+ PUT_BYTE(masklen, data_ptr);
+ PUT_BYTE(curr_bsr_priority, data_ptr);
+ PUT_EUADDR6(curr_bsr_address.sin6_addr, data_ptr);
+
+ /* TODO: XXX: No fragmentation support (yet) */
+
+ for (grp_mask_ptr = grp_mask_list; grp_mask_ptr != (grp_mask_t *) NULL;
+ grp_mask_ptr = grp_mask_ptr->next)
+ {
+ MASK_TO_MASKLEN6(grp_mask_ptr->group_mask, masklen);
+ PUT_EGADDR6(grp_mask_ptr->group_addr.sin6_addr, masklen, 0, data_ptr);
+ PUT_BYTE(grp_mask_ptr->group_rp_number, data_ptr);
+ PUT_BYTE(grp_mask_ptr->group_rp_number, data_ptr); /* TODO: if frag. */
+ PUT_HOSTSHORT(0, data_ptr);
+ for (grp_rp_entry_ptr = grp_mask_ptr->grp_rp_next;
+ grp_rp_entry_ptr != (rp_grp_entry_t *) NULL;
+ grp_rp_entry_ptr = grp_rp_entry_ptr->grp_rp_next)
+ {
+ PUT_EUADDR6(grp_rp_entry_ptr->rp->rpentry->address.sin6_addr, data_ptr);
+ PUT_HOSTSHORT(grp_rp_entry_ptr->advholdtime, data_ptr);
+ PUT_BYTE(grp_rp_entry_ptr->priority, data_ptr);
+ PUT_BYTE(0, data_ptr); /* The reserved field */
+ }
+ }
+
+ datalen = (data_ptr - (u_int8 *) send_buff) - sizeof(struct pim);
+
+ return (datalen);
+}
+
+
+/*
+ * Check if the rp_addr is the RP for the group corresponding to
+ * mrtentry_ptr. Return TRUE or FALSE.
+ */
+
+int
+check_mrtentry_rp(mrtentry_ptr, rp_addr)
+ mrtentry_t *mrtentry_ptr;
+ struct sockaddr_in6 *rp_addr;
+{
+ rp_grp_entry_t *rp_grp_entry_ptr;
+
+ if (mrtentry_ptr == (mrtentry_t *) NULL)
+ return (FALSE);
+ if (IN6_IS_ADDR_UNSPECIFIED(&rp_addr->sin6_addr))
+ return (FALSE);
+ rp_grp_entry_ptr = mrtentry_ptr->group->active_rp_grp;
+ if (rp_grp_entry_ptr == (rp_grp_entry_t *) NULL)
+ return (FALSE);
+ if (inet6_equal(&mrtentry_ptr->group->rpaddr,rp_addr))
+ return (TRUE);
+ return (FALSE);
+}
OpenPOWER on IntegriCloud