summaryrefslogtreecommitdiffstats
path: root/pimd/pim_igmpv3.c
diff options
context:
space:
mode:
authorwhitespace / reindent <invalid@invalid.invalid>2017-07-17 14:03:14 +0200
committerwhitespace / reindent <invalid@invalid.invalid>2017-07-17 14:04:07 +0200
commitd62a17aedeb0eebdba98238874bb13d62c48dbf9 (patch)
tree3b319b1d61c8b85b4d1f06adf8b844bb8a9b5107 /pimd/pim_igmpv3.c
parent*: add indent control files (diff)
downloadfrr-d62a17aedeb0eebdba98238874bb13d62c48dbf9.tar.xz
frr-d62a17aedeb0eebdba98238874bb13d62c48dbf9.zip
indent.py `git ls-files | pcregrep '\.[ch]$' | pcregrep -v '^(ldpd|babeld|nhrpd)/'` Signed-off-by: David Lamparter <equinox@opensourcerouting.org>
Diffstat (limited to 'pimd/pim_igmpv3.c')
-rw-r--r--pimd/pim_igmpv3.c3451
1 files changed, 1759 insertions, 1692 deletions
diff --git a/pimd/pim_igmpv3.c b/pimd/pim_igmpv3.c
index ad37ad876..880d840ea 100644
--- a/pimd/pim_igmpv3.c
+++ b/pimd/pim_igmpv3.c
@@ -39,269 +39,270 @@ static void group_query_send(struct igmp_group *group);
static void source_query_send_by_flag(struct igmp_group *group,
int num_sources_tosend);
-static void on_trace(const char *label,
- struct interface *ifp, struct in_addr from,
- struct in_addr group_addr,
+static void on_trace(const char *label, struct interface *ifp,
+ struct in_addr from, struct in_addr group_addr,
int num_sources, struct in_addr *sources)
{
- if (PIM_DEBUG_IGMP_TRACE) {
- char from_str[INET_ADDRSTRLEN];
- char group_str[INET_ADDRSTRLEN];
+ if (PIM_DEBUG_IGMP_TRACE) {
+ char from_str[INET_ADDRSTRLEN];
+ char group_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<from?>", from, from_str, sizeof(from_str));
- pim_inet4_dump("<group?>", group_addr, group_str, sizeof(group_str));
+ pim_inet4_dump("<from?>", from, from_str, sizeof(from_str));
+ pim_inet4_dump("<group?>", group_addr, group_str,
+ sizeof(group_str));
- zlog_debug("%s: from %s on %s: group=%s sources=%d",
- label, from_str, ifp->name, group_str, num_sources);
- }
+ zlog_debug("%s: from %s on %s: group=%s sources=%d", label,
+ from_str, ifp->name, group_str, num_sources);
+ }
}
void igmp_group_reset_gmi(struct igmp_group *group)
{
- long group_membership_interval_msec;
- struct pim_interface *pim_ifp;
- struct igmp_sock *igmp;
- struct interface *ifp;
-
- igmp = group->group_igmp_sock;
- ifp = igmp->interface;
- pim_ifp = ifp->info;
-
- /*
- RFC 3376: 8.4. Group Membership Interval
-
- The Group Membership Interval is the amount of time that must pass
- before a multicast router decides there are no more members of a
- group or a particular source on a network.
-
- This value MUST be ((the Robustness Variable) times (the Query
- Interval)) plus (one Query Response Interval).
-
- group_membership_interval_msec = querier_robustness_variable *
- (1000 * querier_query_interval) +
- 100 * query_response_interval_dsec;
- */
- group_membership_interval_msec =
- PIM_IGMP_GMI_MSEC(igmp->querier_robustness_variable,
- igmp->querier_query_interval,
- pim_ifp->igmp_query_max_response_time_dsec);
-
- if (PIM_DEBUG_IGMP_TRACE) {
- char group_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
- zlog_debug("Resetting group %s timer to GMI=%ld.%03ld sec on %s",
- group_str,
- group_membership_interval_msec / 1000,
- group_membership_interval_msec % 1000,
- ifp->name);
- }
-
- /*
- RFC 3376: 6.2.2. Definition of Group Timers
-
- The group timer is only used when a group is in EXCLUDE mode and
- it represents the time for the *filter-mode* of the group to
- expire and switch to INCLUDE mode.
- */
- zassert(group->group_filtermode_isexcl);
-
- igmp_group_timer_on(group, group_membership_interval_msec, ifp->name);
+ long group_membership_interval_msec;
+ struct pim_interface *pim_ifp;
+ struct igmp_sock *igmp;
+ struct interface *ifp;
+
+ igmp = group->group_igmp_sock;
+ ifp = igmp->interface;
+ pim_ifp = ifp->info;
+
+ /*
+ RFC 3376: 8.4. Group Membership Interval
+
+ The Group Membership Interval is the amount of time that must pass
+ before a multicast router decides there are no more members of a
+ group or a particular source on a network.
+
+ This value MUST be ((the Robustness Variable) times (the Query
+ Interval)) plus (one Query Response Interval).
+
+ group_membership_interval_msec = querier_robustness_variable *
+ (1000 * querier_query_interval) +
+ 100 * query_response_interval_dsec;
+ */
+ group_membership_interval_msec = PIM_IGMP_GMI_MSEC(
+ igmp->querier_robustness_variable, igmp->querier_query_interval,
+ pim_ifp->igmp_query_max_response_time_dsec);
+
+ if (PIM_DEBUG_IGMP_TRACE) {
+ char group_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<group?>", group->group_addr, group_str,
+ sizeof(group_str));
+ zlog_debug(
+ "Resetting group %s timer to GMI=%ld.%03ld sec on %s",
+ group_str, group_membership_interval_msec / 1000,
+ group_membership_interval_msec % 1000, ifp->name);
+ }
+
+ /*
+ RFC 3376: 6.2.2. Definition of Group Timers
+
+ The group timer is only used when a group is in EXCLUDE mode and
+ it represents the time for the *filter-mode* of the group to
+ expire and switch to INCLUDE mode.
+ */
+ zassert(group->group_filtermode_isexcl);
+
+ igmp_group_timer_on(group, group_membership_interval_msec, ifp->name);
}
static int igmp_source_timer(struct thread *t)
{
- struct igmp_source *source;
- struct igmp_group *group;
-
- source = THREAD_ARG(t);
-
- group = source->source_group;
-
- if (PIM_DEBUG_IGMP_TRACE) {
- char group_str[INET_ADDRSTRLEN];
- char source_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
- pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
- zlog_debug("%s: Source timer expired for group %s source %s on %s",
- __PRETTY_FUNCTION__,
- group_str, source_str,
- group->group_igmp_sock->interface->name);
- }
-
- /*
- RFC 3376: 6.3. IGMPv3 Source-Specific Forwarding Rules
-
- Group
- Filter-Mode Source Timer Value Action
- ----------- ------------------ ------
- INCLUDE TIMER == 0 Suggest to stop forwarding
- traffic from source and
- remove source record. If
- there are no more source
- records for the group, delete
- group record.
-
- EXCLUDE TIMER == 0 Suggest to not forward
- traffic from source
- (DO NOT remove record)
-
- Source timer switched from (T > 0) to (T == 0): disable forwarding.
- */
-
- if (group->group_filtermode_isexcl) {
- /* EXCLUDE mode */
-
- igmp_source_forward_stop(source);
- }
- else {
- /* INCLUDE mode */
-
- /* igmp_source_delete() will stop forwarding source */
- igmp_source_delete(source);
-
- /*
- If there are no more source records for the group, delete group
- record.
- */
- if (!listcount(group->group_source_list)) {
- igmp_group_delete_empty_include(group);
- }
- }
-
- return 0;
+ struct igmp_source *source;
+ struct igmp_group *group;
+
+ source = THREAD_ARG(t);
+
+ group = source->source_group;
+
+ if (PIM_DEBUG_IGMP_TRACE) {
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<group?>", group->group_addr, group_str,
+ sizeof(group_str));
+ pim_inet4_dump("<source?>", source->source_addr, source_str,
+ sizeof(source_str));
+ zlog_debug(
+ "%s: Source timer expired for group %s source %s on %s",
+ __PRETTY_FUNCTION__, group_str, source_str,
+ group->group_igmp_sock->interface->name);
+ }
+
+ /*
+ RFC 3376: 6.3. IGMPv3 Source-Specific Forwarding Rules
+
+ Group
+ Filter-Mode Source Timer Value Action
+ ----------- ------------------ ------
+ INCLUDE TIMER == 0 Suggest to stop forwarding
+ traffic from source and
+ remove source record. If
+ there are no more source
+ records for the group, delete
+ group record.
+
+ EXCLUDE TIMER == 0 Suggest to not forward
+ traffic from source
+ (DO NOT remove record)
+
+ Source timer switched from (T > 0) to (T == 0): disable forwarding.
+ */
+
+ if (group->group_filtermode_isexcl) {
+ /* EXCLUDE mode */
+
+ igmp_source_forward_stop(source);
+ } else {
+ /* INCLUDE mode */
+
+ /* igmp_source_delete() will stop forwarding source */
+ igmp_source_delete(source);
+
+ /*
+ If there are no more source records for the group, delete
+ group
+ record.
+ */
+ if (!listcount(group->group_source_list)) {
+ igmp_group_delete_empty_include(group);
+ }
+ }
+
+ return 0;
}
static void source_timer_off(struct igmp_group *group,
struct igmp_source *source)
{
- if (!source->t_source_timer)
- return;
-
- if (PIM_DEBUG_IGMP_TRACE) {
- char group_str[INET_ADDRSTRLEN];
- char source_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
- pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
- zlog_debug("Cancelling TIMER event for group %s source %s on %s",
- group_str, source_str,
- group->group_igmp_sock->interface->name);
- }
-
- THREAD_OFF(source->t_source_timer);
+ if (!source->t_source_timer)
+ return;
+
+ if (PIM_DEBUG_IGMP_TRACE) {
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<group?>", group->group_addr, group_str,
+ sizeof(group_str));
+ pim_inet4_dump("<source?>", source->source_addr, source_str,
+ sizeof(source_str));
+ zlog_debug(
+ "Cancelling TIMER event for group %s source %s on %s",
+ group_str, source_str,
+ group->group_igmp_sock->interface->name);
+ }
+
+ THREAD_OFF(source->t_source_timer);
}
static void igmp_source_timer_on(struct igmp_group *group,
- struct igmp_source *source,
- long interval_msec)
+ struct igmp_source *source, long interval_msec)
{
- source_timer_off(group, source);
-
- if (PIM_DEBUG_IGMP_EVENTS) {
- char group_str[INET_ADDRSTRLEN];
- char source_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
- pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
- zlog_debug("Scheduling %ld.%03ld sec TIMER event for group %s source %s on %s",
- interval_msec / 1000,
- interval_msec % 1000,
- group_str, source_str,
- group->group_igmp_sock->interface->name);
- }
-
- thread_add_timer_msec(master, igmp_source_timer, source, interval_msec,
- &source->t_source_timer);
-
- /*
- RFC 3376: 6.3. IGMPv3 Source-Specific Forwarding Rules
-
- Source timer switched from (T == 0) to (T > 0): enable forwarding.
- */
- igmp_source_forward_start(source);
+ source_timer_off(group, source);
+
+ if (PIM_DEBUG_IGMP_EVENTS) {
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<group?>", group->group_addr, group_str,
+ sizeof(group_str));
+ pim_inet4_dump("<source?>", source->source_addr, source_str,
+ sizeof(source_str));
+ zlog_debug(
+ "Scheduling %ld.%03ld sec TIMER event for group %s source %s on %s",
+ interval_msec / 1000, interval_msec % 1000, group_str,
+ source_str, group->group_igmp_sock->interface->name);
+ }
+
+ thread_add_timer_msec(master, igmp_source_timer, source, interval_msec,
+ &source->t_source_timer);
+
+ /*
+ RFC 3376: 6.3. IGMPv3 Source-Specific Forwarding Rules
+
+ Source timer switched from (T == 0) to (T > 0): enable forwarding.
+ */
+ igmp_source_forward_start(source);
}
-void igmp_source_reset_gmi(struct igmp_sock *igmp,
- struct igmp_group *group,
+void igmp_source_reset_gmi(struct igmp_sock *igmp, struct igmp_group *group,
struct igmp_source *source)
{
- long group_membership_interval_msec;
- struct pim_interface *pim_ifp;
- struct interface *ifp;
-
- ifp = igmp->interface;
- pim_ifp = ifp->info;
-
- group_membership_interval_msec =
- PIM_IGMP_GMI_MSEC(igmp->querier_robustness_variable,
- igmp->querier_query_interval,
- pim_ifp->igmp_query_max_response_time_dsec);
-
- if (PIM_DEBUG_IGMP_TRACE) {
- char group_str[INET_ADDRSTRLEN];
- char source_str[INET_ADDRSTRLEN];
-
- pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
- pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
-
- zlog_debug("Resetting source %s timer to GMI=%ld.%03ld sec for group %s on %s",
- source_str,
- group_membership_interval_msec / 1000,
- group_membership_interval_msec % 1000,
- group_str,
- ifp->name);
- }
-
- igmp_source_timer_on(group, source,
- group_membership_interval_msec);
+ long group_membership_interval_msec;
+ struct pim_interface *pim_ifp;
+ struct interface *ifp;
+
+ ifp = igmp->interface;
+ pim_ifp = ifp->info;
+
+ group_membership_interval_msec = PIM_IGMP_GMI_MSEC(
+ igmp->querier_robustness_variable, igmp->querier_query_interval,
+ pim_ifp->igmp_query_max_response_time_dsec);
+
+ if (PIM_DEBUG_IGMP_TRACE) {
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
+
+ pim_inet4_dump("<group?>", group->group_addr, group_str,
+ sizeof(group_str));
+ pim_inet4_dump("<source?>", source->source_addr, source_str,
+ sizeof(source_str));
+
+ zlog_debug(
+ "Resetting source %s timer to GMI=%ld.%03ld sec for group %s on %s",
+ source_str, group_membership_interval_msec / 1000,
+ group_membership_interval_msec % 1000, group_str,
+ ifp->name);
+ }
+
+ igmp_source_timer_on(group, source, group_membership_interval_msec);
}
static void source_mark_delete_flag(struct igmp_group *group)
{
- struct listnode *src_node;
- struct igmp_source *src;
+ struct listnode *src_node;
+ struct igmp_source *src;
- for (ALL_LIST_ELEMENTS_RO (group->group_source_list, src_node, src)) {
- IGMP_SOURCE_DO_DELETE(src->source_flags);
- }
+ for (ALL_LIST_ELEMENTS_RO(group->group_source_list, src_node, src)) {
+ IGMP_SOURCE_DO_DELETE(src->source_flags);
+ }
}
-static void source_mark_send_flag (struct igmp_group *group)
+static void source_mark_send_flag(struct igmp_group *group)
{
- struct listnode *src_node;
- struct igmp_source *src;
+ struct listnode *src_node;
+ struct igmp_source *src;
- for (ALL_LIST_ELEMENTS_RO (group->group_source_list, src_node, src)) {
- IGMP_SOURCE_DO_SEND(src->source_flags);
- }
+ for (ALL_LIST_ELEMENTS_RO(group->group_source_list, src_node, src)) {
+ IGMP_SOURCE_DO_SEND(src->source_flags);
+ }
}
-static int source_mark_send_flag_by_timer (struct igmp_group *group)
+static int source_mark_send_flag_by_timer(struct igmp_group *group)
{
- struct listnode *src_node;
- struct igmp_source *src;
- int num_marked_sources = 0;
-
- for (ALL_LIST_ELEMENTS_RO(group->group_source_list, src_node, src)) {
- /* Is source timer running? */
- if (src->t_source_timer) {
- IGMP_SOURCE_DO_SEND(src->source_flags);
- ++num_marked_sources;
- }
- else {
- IGMP_SOURCE_DONT_SEND(src->source_flags);
- }
- }
-
- return num_marked_sources;
+ struct listnode *src_node;
+ struct igmp_source *src;
+ int num_marked_sources = 0;
+
+ for (ALL_LIST_ELEMENTS_RO(group->group_source_list, src_node, src)) {
+ /* Is source timer running? */
+ if (src->t_source_timer) {
+ IGMP_SOURCE_DO_SEND(src->source_flags);
+ ++num_marked_sources;
+ } else {
+ IGMP_SOURCE_DONT_SEND(src->source_flags);
+ }
+ }
+
+ return num_marked_sources;
}
static void source_clear_send_flag(struct list *source_list)
{
- struct listnode *src_node;
- struct igmp_source *src;
+ struct listnode *src_node;
+ struct igmp_source *src;
- for (ALL_LIST_ELEMENTS_RO(source_list, src_node, src)) {
- IGMP_SOURCE_DONT_SEND(src->source_flags);
- }
+ for (ALL_LIST_ELEMENTS_RO(source_list, src_node, src)) {
+ IGMP_SOURCE_DONT_SEND(src->source_flags);
+ }
}
/*
@@ -309,27 +310,27 @@ static void source_clear_send_flag(struct list *source_list)
*/
static void group_exclude_fwd_anysrc_ifempty(struct igmp_group *group)
{
- zassert(group->group_filtermode_isexcl);
+ zassert(group->group_filtermode_isexcl);
- if (listcount(group->group_source_list) < 1) {
- igmp_anysource_forward_start(group);
- }
+ if (listcount(group->group_source_list) < 1) {
+ igmp_anysource_forward_start(group);
+ }
}
void igmp_source_free(struct igmp_source *source)
{
- /* make sure there is no source timer running */
- zassert(!source->t_source_timer);
+ /* make sure there is no source timer running */
+ zassert(!source->t_source_timer);
- XFREE(MTYPE_PIM_IGMP_GROUP_SOURCE, source);
+ XFREE(MTYPE_PIM_IGMP_GROUP_SOURCE, source);
}
static void source_channel_oil_detach(struct igmp_source *source)
{
- if (source->source_channel_oil) {
- pim_channel_oil_del(source->source_channel_oil);
- source->source_channel_oil = NULL;
- }
+ if (source->source_channel_oil) {
+ pim_channel_oil_del(source->source_channel_oil);
+ source->source_channel_oil = NULL;
+ }
}
/*
@@ -338,662 +339,659 @@ static void source_channel_oil_detach(struct igmp_source *source)
*/
void igmp_source_delete(struct igmp_source *source)
{
- struct igmp_group *group;
- struct in_addr src;
-
- group = source->source_group;
-
- if (PIM_DEBUG_IGMP_TRACE) {
- char group_str[INET_ADDRSTRLEN];
- char source_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
- pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
- zlog_debug("Deleting IGMP source %s for group %s from socket %d interface %s c_oil ref_count %d",
- source_str, group_str,
- group->group_igmp_sock->fd,
- group->group_igmp_sock->interface->name,
- source->source_channel_oil ? source->source_channel_oil->oil_ref_count : 0);
- }
-
- source_timer_off(group, source);
- igmp_source_forward_stop(source);
-
- /* sanity check that forwarding has been disabled */
- if (IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
- char group_str[INET_ADDRSTRLEN];
- char source_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
- pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
- zlog_warn("%s: forwarding=ON(!) IGMP source %s for group %s from socket %d interface %s",
- __PRETTY_FUNCTION__,
- source_str, group_str,
- group->group_igmp_sock->fd,
- group->group_igmp_sock->interface->name);
- /* warning only */
- }
-
- source_channel_oil_detach(source);
-
- /*
- notice that listnode_delete() can't be moved
- into igmp_source_free() because the later is
- called by list_delete_all_node()
- */
- listnode_delete(group->group_source_list, source);
-
- src.s_addr = source->source_addr.s_addr;
- igmp_source_free(source);
-
- /* Group source list is empty and current source is * then
- *,G group going away so do not trigger start */
- if (group->group_filtermode_isexcl &&
- (listcount (group->group_source_list) != 0) &&
- src.s_addr != INADDR_ANY)
- {
- group_exclude_fwd_anysrc_ifempty (group);
- }
+ struct igmp_group *group;
+ struct in_addr src;
+
+ group = source->source_group;
+
+ if (PIM_DEBUG_IGMP_TRACE) {
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<group?>", group->group_addr, group_str,
+ sizeof(group_str));
+ pim_inet4_dump("<source?>", source->source_addr, source_str,
+ sizeof(source_str));
+ zlog_debug(
+ "Deleting IGMP source %s for group %s from socket %d interface %s c_oil ref_count %d",
+ source_str, group_str, group->group_igmp_sock->fd,
+ group->group_igmp_sock->interface->name,
+ source->source_channel_oil
+ ? source->source_channel_oil->oil_ref_count
+ : 0);
+ }
+
+ source_timer_off(group, source);
+ igmp_source_forward_stop(source);
+
+ /* sanity check that forwarding has been disabled */
+ if (IGMP_SOURCE_TEST_FORWARDING(source->source_flags)) {
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<group?>", group->group_addr, group_str,
+ sizeof(group_str));
+ pim_inet4_dump("<source?>", source->source_addr, source_str,
+ sizeof(source_str));
+ zlog_warn(
+ "%s: forwarding=ON(!) IGMP source %s for group %s from socket %d interface %s",
+ __PRETTY_FUNCTION__, source_str, group_str,
+ group->group_igmp_sock->fd,
+ group->group_igmp_sock->interface->name);
+ /* warning only */
+ }
+
+ source_channel_oil_detach(source);
+
+ /*
+ notice that listnode_delete() can't be moved
+ into igmp_source_free() because the later is
+ called by list_delete_all_node()
+ */
+ listnode_delete(group->group_source_list, source);
+
+ src.s_addr = source->source_addr.s_addr;
+ igmp_source_free(source);
+
+ /* Group source list is empty and current source is * then
+ *,G group going away so do not trigger start */
+ if (group->group_filtermode_isexcl
+ && (listcount(group->group_source_list) != 0)
+ && src.s_addr != INADDR_ANY) {
+ group_exclude_fwd_anysrc_ifempty(group);
+ }
}
static void source_delete_by_flag(struct list *source_list)
{
- struct listnode *src_node;
- struct listnode *src_nextnode;
- struct igmp_source *src;
-
- for (ALL_LIST_ELEMENTS(source_list, src_node, src_nextnode, src))
- if (IGMP_SOURCE_TEST_DELETE(src->source_flags))
- igmp_source_delete(src);
+ struct listnode *src_node;
+ struct listnode *src_nextnode;
+ struct igmp_source *src;
+
+ for (ALL_LIST_ELEMENTS(source_list, src_node, src_nextnode, src))
+ if (IGMP_SOURCE_TEST_DELETE(src->source_flags))
+ igmp_source_delete(src);
}
void igmp_source_delete_expired(struct list *source_list)
{
- struct listnode *src_node;
- struct listnode *src_nextnode;
- struct igmp_source *src;
-
- for (ALL_LIST_ELEMENTS(source_list, src_node, src_nextnode, src))
- if (!src->t_source_timer)
- igmp_source_delete(src);
+ struct listnode *src_node;
+ struct listnode *src_nextnode;
+ struct igmp_source *src;
+
+ for (ALL_LIST_ELEMENTS(source_list, src_node, src_nextnode, src))
+ if (!src->t_source_timer)
+ igmp_source_delete(src);
}
struct igmp_source *igmp_find_source_by_addr(struct igmp_group *group,
struct in_addr src_addr)
{
- struct listnode *src_node;
- struct igmp_source *src;
+ struct listnode *src_node;
+ struct igmp_source *src;
- for (ALL_LIST_ELEMENTS_RO(group->group_source_list, src_node, src))
- if (src_addr.s_addr == src->source_addr.s_addr)
- return src;
+ for (ALL_LIST_ELEMENTS_RO(group->group_source_list, src_node, src))
+ if (src_addr.s_addr == src->source_addr.s_addr)
+ return src;
- return 0;
+ return 0;
}
-struct igmp_source *
-source_new (struct igmp_group *group,
- struct in_addr src_addr)
+struct igmp_source *source_new(struct igmp_group *group,
+ struct in_addr src_addr)
{
- struct igmp_source *src;
-
- if (PIM_DEBUG_IGMP_TRACE) {
- char group_str[INET_ADDRSTRLEN];
- char source_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
- pim_inet4_dump("<source?>", src_addr, source_str, sizeof(source_str));
- zlog_debug("Creating new IGMP source %s for group %s on socket %d interface %s",
- source_str, group_str,
- group->group_igmp_sock->fd,
- group->group_igmp_sock->interface->name);
- }
-
- src = XCALLOC(MTYPE_PIM_IGMP_GROUP_SOURCE, sizeof(*src));
- if (!src) {
- zlog_warn("%s %s: XCALLOC() failure",
- __FILE__, __PRETTY_FUNCTION__);
- return 0; /* error, not found, could not create */
- }
-
- src->t_source_timer = NULL;
- src->source_group = group; /* back pointer */
- src->source_addr = src_addr;
- src->source_creation = pim_time_monotonic_sec();
- src->source_flags = 0;
- src->source_query_retransmit_count = 0;
- src->source_channel_oil = NULL;
-
- listnode_add(group->group_source_list, src);
-
- /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
- igmp_anysource_forward_stop(group);
-
- return src;
+ struct igmp_source *src;
+
+ if (PIM_DEBUG_IGMP_TRACE) {
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<group?>", group->group_addr, group_str,
+ sizeof(group_str));
+ pim_inet4_dump("<source?>", src_addr, source_str,
+ sizeof(source_str));
+ zlog_debug(
+ "Creating new IGMP source %s for group %s on socket %d interface %s",
+ source_str, group_str, group->group_igmp_sock->fd,
+ group->group_igmp_sock->interface->name);
+ }
+
+ src = XCALLOC(MTYPE_PIM_IGMP_GROUP_SOURCE, sizeof(*src));
+ if (!src) {
+ zlog_warn("%s %s: XCALLOC() failure", __FILE__,
+ __PRETTY_FUNCTION__);
+ return 0; /* error, not found, could not create */
+ }
+
+ src->t_source_timer = NULL;
+ src->source_group = group; /* back pointer */
+ src->source_addr = src_addr;
+ src->source_creation = pim_time_monotonic_sec();
+ src->source_flags = 0;
+ src->source_query_retransmit_count = 0;
+ src->source_channel_oil = NULL;
+
+ listnode_add(group->group_source_list, src);
+
+ /* Any source (*,G) is forwarded only if mode is EXCLUDE {empty} */
+ igmp_anysource_forward_stop(group);
+
+ return src;
}
static struct igmp_source *add_source_by_addr(struct igmp_sock *igmp,
struct igmp_group *group,
struct in_addr src_addr)
{
- struct igmp_source *src;
+ struct igmp_source *src;
- src = igmp_find_source_by_addr(group, src_addr);
- if (src) {
- return src;
- }
+ src = igmp_find_source_by_addr(group, src_addr);
+ if (src) {
+ return src;
+ }
- src = source_new(group, src_addr);
- if (!src) {
- return 0;
- }
+ src = source_new(group, src_addr);
+ if (!src) {
+ return 0;
+ }
- return src;
+ return src;
}
static void allow(struct igmp_sock *igmp, struct in_addr from,
- struct in_addr group_addr,
- int num_sources, struct in_addr *sources)
+ struct in_addr group_addr, int num_sources,
+ struct in_addr *sources)
{
- struct igmp_source *source;
- struct igmp_group *group;
- int i;
-
- /* non-existant group is created as INCLUDE {empty} */
- group = igmp_add_group_by_addr(igmp, group_addr);
- if (!group) {
- return;
- }
-
- /* scan received sources */
- for (i = 0; i < num_sources; ++i) {
- struct in_addr *src_addr;
-
- src_addr = sources + i;
-
- source = add_source_by_addr(igmp, group, *src_addr);
- if (!source) {
- continue;
- }
-
- /*
- RFC 3376: 6.4.1. Reception of Current-State Records
-
- When receiving IS_IN reports for groups in EXCLUDE mode is
- sources should be moved from set with (timers = 0) to set with
- (timers > 0).
-
- igmp_source_reset_gmi() below, resetting the source timers to
- GMI, accomplishes this.
- */
- igmp_source_reset_gmi(igmp, group, source);
-
- } /* scan received sources */
-
- if ((num_sources == 0) &&
- (group->group_filtermode_isexcl) &&
- (listcount (group->group_source_list) == 1))
- {
- struct in_addr star = { .s_addr = INADDR_ANY };
-
- source = igmp_find_source_by_addr (group, star);
- if (source)
- igmp_source_reset_gmi (igmp, group, source);
- }
+ struct igmp_source *source;
+ struct igmp_group *group;
+ int i;
+
+ /* non-existant group is created as INCLUDE {empty} */
+ group = igmp_add_group_by_addr(igmp, group_addr);
+ if (!group) {
+ return;
+ }
+
+ /* scan received sources */
+ for (i = 0; i < num_sources; ++i) {
+ struct in_addr *src_addr;
+
+ src_addr = sources + i;
+
+ source = add_source_by_addr(igmp, group, *src_addr);
+ if (!source) {
+ continue;
+ }
+
+ /*
+ RFC 3376: 6.4.1. Reception of Current-State Records
+
+ When receiving IS_IN reports for groups in EXCLUDE mode is
+ sources should be moved from set with (timers = 0) to set with
+ (timers > 0).
+
+ igmp_source_reset_gmi() below, resetting the source timers to
+ GMI, accomplishes this.
+ */
+ igmp_source_reset_gmi(igmp, group, source);
+
+ } /* scan received sources */
+
+ if ((num_sources == 0) && (group->group_filtermode_isexcl)
+ && (listcount(group->group_source_list) == 1)) {
+ struct in_addr star = {.s_addr = INADDR_ANY};
+
+ source = igmp_find_source_by_addr(group, star);
+ if (source)
+ igmp_source_reset_gmi(igmp, group, source);
+ }
}
void igmpv3_report_isin(struct igmp_sock *igmp, struct in_addr from,
- struct in_addr group_addr,
- int num_sources, struct in_addr *sources)
+ struct in_addr group_addr, int num_sources,
+ struct in_addr *sources)
{
- on_trace(__PRETTY_FUNCTION__,
- igmp->interface, from, group_addr, num_sources, sources);
+ on_trace(__PRETTY_FUNCTION__, igmp->interface, from, group_addr,
+ num_sources, sources);
- allow(igmp, from, group_addr, num_sources, sources);
+ allow(igmp, from, group_addr, num_sources, sources);
}
-static void isex_excl(struct igmp_group *group,
- int num_sources, struct in_addr *sources)
+static void isex_excl(struct igmp_group *group, int num_sources,
+ struct in_addr *sources)
{
- struct igmp_source *source;
- int i;
-
- /* EXCLUDE mode */
- zassert(group->group_filtermode_isexcl);
-
- /* E.1: set deletion flag for known sources (X,Y) */
- source_mark_delete_flag (group);
-
- /* scan received sources (A) */
- for (i = 0; i < num_sources; ++i) {
- struct in_addr *src_addr;
-
- src_addr = sources + i;
-
- /* E.2: lookup reported source from (A) in (X,Y) */
- source = igmp_find_source_by_addr(group, *src_addr);
- if (source) {
- /* E.3: if found, clear deletion flag: (X*A) or (Y*A) */
- IGMP_SOURCE_DONT_DELETE(source->source_flags);
- }
- else {
- /* E.4: if not found, create source with timer=GMI: (A-X-Y) */
- source = source_new(group, *src_addr);
- if (!source) {
- /* ugh, internal malloc failure, skip source */
- continue;
- }
- zassert(!source->t_source_timer); /* timer == 0 */
- igmp_source_reset_gmi(group->group_igmp_sock, group, source);
- zassert(source->t_source_timer); /* (A-X-Y) timer > 0 */
- }
-
- } /* scan received sources */
-
- /*
- * If we are in isexcl mode and num_sources == 0
- * than that means we have a *,g entry that
- * needs to be handled
- */
- if (group->group_filtermode_isexcl && num_sources == 0)
- {
- struct in_addr star = { .s_addr = INADDR_ANY };
- source = igmp_find_source_by_addr (group, star);
- if (source)
- {
- IGMP_SOURCE_DONT_DELETE(source->source_flags);
- igmp_source_reset_gmi (group->group_igmp_sock, group, source);
- }
- }
-
- /* E.5: delete all sources marked with deletion flag: (X-A) and (Y-A) */
- source_delete_by_flag(group->group_source_list);
+ struct igmp_source *source;
+ int i;
+
+ /* EXCLUDE mode */
+ zassert(group->group_filtermode_isexcl);
+
+ /* E.1: set deletion flag for known sources (X,Y) */
+ source_mark_delete_flag(group);
+
+ /* scan received sources (A) */
+ for (i = 0; i < num_sources; ++i) {
+ struct in_addr *src_addr;
+
+ src_addr = sources + i;
+
+ /* E.2: lookup reported source from (A) in (X,Y) */
+ source = igmp_find_source_by_addr(group, *src_addr);
+ if (source) {
+ /* E.3: if found, clear deletion flag: (X*A) or (Y*A) */
+ IGMP_SOURCE_DONT_DELETE(source->source_flags);
+ } else {
+ /* E.4: if not found, create source with timer=GMI:
+ * (A-X-Y) */
+ source = source_new(group, *src_addr);
+ if (!source) {
+ /* ugh, internal malloc failure, skip source */
+ continue;
+ }
+ zassert(!source->t_source_timer); /* timer == 0 */
+ igmp_source_reset_gmi(group->group_igmp_sock, group,
+ source);
+ zassert(source->t_source_timer); /* (A-X-Y) timer > 0 */
+ }
+
+ } /* scan received sources */
+
+ /*
+ * If we are in isexcl mode and num_sources == 0
+ * than that means we have a *,g entry that
+ * needs to be handled
+ */
+ if (group->group_filtermode_isexcl && num_sources == 0) {
+ struct in_addr star = {.s_addr = INADDR_ANY};
+ source = igmp_find_source_by_addr(group, star);
+ if (source) {
+ IGMP_SOURCE_DONT_DELETE(source->source_flags);
+ igmp_source_reset_gmi(group->group_igmp_sock, group,
+ source);
+ }
+ }
+
+ /* E.5: delete all sources marked with deletion flag: (X-A) and (Y-A) */
+ source_delete_by_flag(group->group_source_list);
}
-static void isex_incl(struct igmp_group *group,
- int num_sources, struct in_addr *sources)
+static void isex_incl(struct igmp_group *group, int num_sources,
+ struct in_addr *sources)
{
- int i;
-
- /* INCLUDE mode */
- zassert(!group->group_filtermode_isexcl);
-
- /* I.1: set deletion flag for known sources (A) */
- source_mark_delete_flag (group);
-
- /* scan received sources (B) */
- for (i = 0; i < num_sources; ++i) {
- struct igmp_source *source;
- struct in_addr *src_addr;
-
- src_addr = sources + i;
-
- /* I.2: lookup reported source (B) */
- source = igmp_find_source_by_addr(group, *src_addr);
- if (source) {
- /* I.3: if found, clear deletion flag (A*B) */
- IGMP_SOURCE_DONT_DELETE(source->source_flags);
- }
- else {
- /* I.4: if not found, create source with timer=0 (B-A) */
- source = source_new(group, *src_addr);
- if (!source) {
- /* ugh, internal malloc failure, skip source */
- continue;
- }
- zassert(!source->t_source_timer); /* (B-A) timer=0 */
- }
-
- } /* scan received sources */
-
- /* I.5: delete all sources marked with deletion flag (A-B) */
- source_delete_by_flag(group->group_source_list);
-
- group->group_filtermode_isexcl = 1; /* boolean=true */
-
- zassert(group->group_filtermode_isexcl);
-
- group_exclude_fwd_anysrc_ifempty(group);
+ int i;
+
+ /* INCLUDE mode */
+ zassert(!group->group_filtermode_isexcl);
+
+ /* I.1: set deletion flag for known sources (A) */
+ source_mark_delete_flag(group);
+
+ /* scan received sources (B) */
+ for (i = 0; i < num_sources; ++i) {
+ struct igmp_source *source;
+ struct in_addr *src_addr;
+
+ src_addr = sources + i;
+
+ /* I.2: lookup reported source (B) */
+ source = igmp_find_source_by_addr(group, *src_addr);
+ if (source) {
+ /* I.3: if found, clear deletion flag (A*B) */
+ IGMP_SOURCE_DONT_DELETE(source->source_flags);
+ } else {
+ /* I.4: if not found, create source with timer=0 (B-A)
+ */
+ source = source_new(group, *src_addr);
+ if (!source) {
+ /* ugh, internal malloc failure, skip source */
+ continue;
+ }
+ zassert(!source->t_source_timer); /* (B-A) timer=0 */
+ }
+
+ } /* scan received sources */
+
+ /* I.5: delete all sources marked with deletion flag (A-B) */
+ source_delete_by_flag(group->group_source_list);
+
+ group->group_filtermode_isexcl = 1; /* boolean=true */
+
+ zassert(group->group_filtermode_isexcl);
+
+ group_exclude_fwd_anysrc_ifempty(group);
}
void igmpv3_report_isex(struct igmp_sock *igmp, struct in_addr from,
- struct in_addr group_addr,
- int num_sources, struct in_addr *sources,
- int from_igmp_v2_report)
+ struct in_addr group_addr, int num_sources,
+ struct in_addr *sources, int from_igmp_v2_report)
{
- struct interface *ifp = igmp->interface;
- struct igmp_group *group;
-
- on_trace(__PRETTY_FUNCTION__,
- ifp, from, group_addr, num_sources, sources);
-
- /* non-existant group is created as INCLUDE {empty} */
- group = igmp_add_group_by_addr(igmp, group_addr);
- if (!group) {
- return;
- }
-
- /* So we can display how we learned the group in our show command output */
- if (from_igmp_v2_report)
- group->igmp_version = 2;
-
- if (group->group_filtermode_isexcl) {
- /* EXCLUDE mode */
- isex_excl(group, num_sources, sources);
- }
- else {
- /* INCLUDE mode */
- isex_incl(group, num_sources, sources);
- zassert(group->group_filtermode_isexcl);
- }
-
- zassert(group->group_filtermode_isexcl);
-
- igmp_group_reset_gmi(group);
+ struct interface *ifp = igmp->interface;
+ struct igmp_group *group;
+
+ on_trace(__PRETTY_FUNCTION__, ifp, from, group_addr, num_sources,
+ sources);
+
+ /* non-existant group is created as INCLUDE {empty} */
+ group = igmp_add_group_by_addr(igmp, group_addr);
+ if (!group) {
+ return;
+ }
+
+ /* So we can display how we learned the group in our show command output
+ */
+ if (from_igmp_v2_report)
+ group->igmp_version = 2;
+
+ if (group->group_filtermode_isexcl) {
+ /* EXCLUDE mode */
+ isex_excl(group, num_sources, sources);
+ } else {
+ /* INCLUDE mode */
+ isex_incl(group, num_sources, sources);
+ zassert(group->group_filtermode_isexcl);
+ }
+
+ zassert(group->group_filtermode_isexcl);
+
+ igmp_group_reset_gmi(group);
}
-static void toin_incl(struct igmp_group *group,
- int num_sources, struct in_addr *sources)
+static void toin_incl(struct igmp_group *group, int num_sources,
+ struct in_addr *sources)
{
- struct igmp_sock *igmp = group->group_igmp_sock;
- int num_sources_tosend = listcount(group->group_source_list);
- int i;
-
- /* Set SEND flag for all known sources (A) */
- source_mark_send_flag (group);
-
- /* Scan received sources (B) */
- for (i = 0; i < num_sources; ++i) {
- struct igmp_source *source;
- struct in_addr *src_addr;
-
- src_addr = sources + i;
-
- /* Lookup reported source (B) */
- source = igmp_find_source_by_addr(group, *src_addr);
- if (source) {
- /* If found, clear SEND flag (A*B) */
- IGMP_SOURCE_DONT_SEND(source->source_flags);
- --num_sources_tosend;
- }
- else {
- /* If not found, create new source */
- source = source_new(group, *src_addr);
- if (!source) {
- /* ugh, internal malloc failure, skip source */
- continue;
- }
- }
-
- /* (B)=GMI */
- igmp_source_reset_gmi(igmp, group, source);
- }
-
- /* Send sources marked with SEND flag: Q(G,A-B) */
- if (num_sources_tosend > 0) {
- source_query_send_by_flag(group, num_sources_tosend);
- }
+ struct igmp_sock *igmp = group->group_igmp_sock;
+ int num_sources_tosend = listcount(group->group_source_list);
+ int i;
+
+ /* Set SEND flag for all known sources (A) */
+ source_mark_send_flag(group);
+
+ /* Scan received sources (B) */
+ for (i = 0; i < num_sources; ++i) {
+ struct igmp_source *source;
+ struct in_addr *src_addr;
+
+ src_addr = sources + i;
+
+ /* Lookup reported source (B) */
+ source = igmp_find_source_by_addr(group, *src_addr);
+ if (source) {
+ /* If found, clear SEND flag (A*B) */
+ IGMP_SOURCE_DONT_SEND(source->source_flags);
+ --num_sources_tosend;
+ } else {
+ /* If not found, create new source */
+ source = source_new(group, *src_addr);
+ if (!source) {
+ /* ugh, internal malloc failure, skip source */
+ continue;
+ }
+ }
+
+ /* (B)=GMI */
+ igmp_source_reset_gmi(igmp, group, source);
+ }
+
+ /* Send sources marked with SEND flag: Q(G,A-B) */
+ if (num_sources_tosend > 0) {
+ source_query_send_by_flag(group, num_sources_tosend);
+ }
}
-static void toin_excl(struct igmp_group *group,
- int num_sources, struct in_addr *sources)
+static void toin_excl(struct igmp_group *group, int num_sources,
+ struct in_addr *sources)
{
- struct igmp_sock *igmp = group->group_igmp_sock;
- int num_sources_tosend;
- int i;
-
- /* Set SEND flag for X (sources with timer > 0) */
- num_sources_tosend = source_mark_send_flag_by_timer (group);
-
- /* Scan received sources (A) */
- for (i = 0; i < num_sources; ++i) {
- struct igmp_source *source;
- struct in_addr *src_addr;
-
- src_addr = sources + i;
-
- /* Lookup reported source (A) */
- source = igmp_find_source_by_addr(group, *src_addr);
- if (source) {
- if (source->t_source_timer) {
- /* If found and timer running, clear SEND flag (X*A) */
- IGMP_SOURCE_DONT_SEND(source->source_flags);
- --num_sources_tosend;
- }
- }
- else {
- /* If not found, create new source */
- source = source_new(group, *src_addr);
- if (!source) {
- /* ugh, internal malloc failure, skip source */
- continue;
- }
- }
-
- /* (A)=GMI */
- igmp_source_reset_gmi(igmp, group, source);
- }
-
- /* Send sources marked with SEND flag: Q(G,X-A) */
- if (num_sources_tosend > 0) {
- source_query_send_by_flag(group, num_sources_tosend);
- }
-
- /* Send Q(G) */
- group_query_send(group);
+ struct igmp_sock *igmp = group->group_igmp_sock;
+ int num_sources_tosend;
+ int i;
+
+ /* Set SEND flag for X (sources with timer > 0) */
+ num_sources_tosend = source_mark_send_flag_by_timer(group);
+
+ /* Scan received sources (A) */
+ for (i = 0; i < num_sources; ++i) {
+ struct igmp_source *source;
+ struct in_addr *src_addr;
+
+ src_addr = sources + i;
+
+ /* Lookup reported source (A) */
+ source = igmp_find_source_by_addr(group, *src_addr);
+ if (source) {
+ if (source->t_source_timer) {
+ /* If found and timer running, clear SEND flag
+ * (X*A) */
+ IGMP_SOURCE_DONT_SEND(source->source_flags);
+ --num_sources_tosend;
+ }
+ } else {
+ /* If not found, create new source */
+ source = source_new(group, *src_addr);
+ if (!source) {
+ /* ugh, internal malloc failure, skip source */
+ continue;
+ }
+ }
+
+ /* (A)=GMI */
+ igmp_source_reset_gmi(igmp, group, source);
+ }
+
+ /* Send sources marked with SEND flag: Q(G,X-A) */
+ if (num_sources_tosend > 0) {
+ source_query_send_by_flag(group, num_sources_tosend);
+ }
+
+ /* Send Q(G) */
+ group_query_send(group);
}
void igmpv3_report_toin(struct igmp_sock *igmp, struct in_addr from,
- struct in_addr group_addr,
- int num_sources, struct in_addr *sources)
+ struct in_addr group_addr, int num_sources,
+ struct in_addr *sources)
{
- struct interface *ifp = igmp->interface;
- struct igmp_group *group;
-
- on_trace(__PRETTY_FUNCTION__,
- ifp, from, group_addr, num_sources, sources);
-
- /*
- * If the requested filter mode is INCLUDE *and* the requested source
- * list is empty, then the entry corresponding to the requested
- * interface and multicast address is deleted if present. If no such
- * entry is present, the request is ignored.
- */
- if (num_sources)
- {
- /* non-existant group is created as INCLUDE {empty} */
- group = igmp_add_group_by_addr(igmp, group_addr);
- if (!group) {
- return;
- }
- }
- else
- {
- group = find_group_by_addr (igmp, group_addr);
- if (!group)
- return;
- }
-
- if (group->group_filtermode_isexcl) {
- /* EXCLUDE mode */
- toin_excl(group, num_sources, sources);
- }
- else {
- /* INCLUDE mode */
- toin_incl(group, num_sources, sources);
- }
+ struct interface *ifp = igmp->interface;
+ struct igmp_group *group;
+
+ on_trace(__PRETTY_FUNCTION__, ifp, from, group_addr, num_sources,
+ sources);
+
+ /*
+ * If the requested filter mode is INCLUDE *and* the requested source
+ * list is empty, then the entry corresponding to the requested
+ * interface and multicast address is deleted if present. If no such
+ * entry is present, the request is ignored.
+ */
+ if (num_sources) {
+ /* non-existant group is created as INCLUDE {empty} */
+ group = igmp_add_group_by_addr(igmp, group_addr);
+ if (!group) {
+ return;
+ }
+ } else {
+ group = find_group_by_addr(igmp, group_addr);
+ if (!group)
+ return;
+ }
+
+ if (group->group_filtermode_isexcl) {
+ /* EXCLUDE mode */
+ toin_excl(group, num_sources, sources);
+ } else {
+ /* INCLUDE mode */
+ toin_incl(group, num_sources, sources);
+ }
}
-static void toex_incl(struct igmp_group *group,
- int num_sources, struct in_addr *sources)
+static void toex_incl(struct igmp_group *group, int num_sources,
+ struct in_addr *sources)
{
- int num_sources_tosend = 0;
- int i;
-
- zassert(!group->group_filtermode_isexcl);
-
- /* Set DELETE flag for all known sources (A) */
- source_mark_delete_flag (group);
-
- /* Clear off SEND flag from all known sources (A) */
- source_clear_send_flag(group->group_source_list);
-
- /* Scan received sources (B) */
- for (i = 0; i < num_sources; ++i) {
- struct igmp_source *source;
- struct in_addr *src_addr;
-
- src_addr = sources + i;
-
- /* Lookup reported source (B) */
- source = igmp_find_source_by_addr(group, *src_addr);
- if (source) {
- /* If found, clear deletion flag: (A*B) */
- IGMP_SOURCE_DONT_DELETE(source->source_flags);
- /* and set SEND flag (A*B) */
- IGMP_SOURCE_DO_SEND(source->source_flags);
- ++num_sources_tosend;
- }
- else {
- /* If source not found, create source with timer=0: (B-A)=0 */
- source = source_new(group, *src_addr);
- if (!source) {
- /* ugh, internal malloc failure, skip source */
- continue;
- }
- zassert(!source->t_source_timer); /* (B-A) timer=0 */
- }
-
- } /* Scan received sources (B) */
-
- group->group_filtermode_isexcl = 1; /* boolean=true */
-
- /* Delete all sources marked with DELETE flag (A-B) */
- source_delete_by_flag(group->group_source_list);
-
- /* Send sources marked with SEND flag: Q(G,A*B) */
- if (num_sources_tosend > 0) {
- source_query_send_by_flag(group, num_sources_tosend);
- }
-
- zassert(group->group_filtermode_isexcl);
-
- group_exclude_fwd_anysrc_ifempty(group);
+ int num_sources_tosend = 0;
+ int i;
+
+ zassert(!group->group_filtermode_isexcl);
+
+ /* Set DELETE flag for all known sources (A) */
+ source_mark_delete_flag(group);
+
+ /* Clear off SEND flag from all known sources (A) */
+ source_clear_send_flag(group->group_source_list);
+
+ /* Scan received sources (B) */
+ for (i = 0; i < num_sources; ++i) {
+ struct igmp_source *source;
+ struct in_addr *src_addr;
+
+ src_addr = sources + i;
+
+ /* Lookup reported source (B) */
+ source = igmp_find_source_by_addr(group, *src_addr);
+ if (source) {
+ /* If found, clear deletion flag: (A*B) */
+ IGMP_SOURCE_DONT_DELETE(source->source_flags);
+ /* and set SEND flag (A*B) */
+ IGMP_SOURCE_DO_SEND(source->source_flags);
+ ++num_sources_tosend;
+ } else {
+ /* If source not found, create source with timer=0:
+ * (B-A)=0 */
+ source = source_new(group, *src_addr);
+ if (!source) {
+ /* ugh, internal malloc failure, skip source */
+ continue;
+ }
+ zassert(!source->t_source_timer); /* (B-A) timer=0 */
+ }
+
+ } /* Scan received sources (B) */
+
+ group->group_filtermode_isexcl = 1; /* boolean=true */
+
+ /* Delete all sources marked with DELETE flag (A-B) */
+ source_delete_by_flag(group->group_source_list);
+
+ /* Send sources marked with SEND flag: Q(G,A*B) */
+ if (num_sources_tosend > 0) {
+ source_query_send_by_flag(group, num_sources_tosend);
+ }
+
+ zassert(group->group_filtermode_isexcl);
+
+ group_exclude_fwd_anysrc_ifempty(group);
}
-static void toex_excl(struct igmp_group *group,
- int num_sources, struct in_addr *sources)
+static void toex_excl(struct igmp_group *group, int num_sources,
+ struct in_addr *sources)
{
- int num_sources_tosend = 0;
- int i;
-
- /* set DELETE flag for all known sources (X,Y) */
- source_mark_delete_flag (group);
-
- /* clear off SEND flag from all known sources (X,Y) */
- source_clear_send_flag(group->group_source_list);
-
- if (num_sources == 0)
- {
- struct igmp_source *source;
- struct in_addr any = { .s_addr = INADDR_ANY };
-
- source = igmp_find_source_by_addr (group, any);
- if (source)
- IGMP_SOURCE_DONT_DELETE(source->source_flags);
- }
-
- /* scan received sources (A) */
- for (i = 0; i < num_sources; ++i) {
- struct igmp_source *source;
- struct in_addr *src_addr;
-
- src_addr = sources + i;
-
- /* lookup reported source (A) in known sources (X,Y) */
- source = igmp_find_source_by_addr(group, *src_addr);
- if (source) {
- /* if found, clear off DELETE flag from reported source (A) */
- IGMP_SOURCE_DONT_DELETE(source->source_flags);
- }
- else {
- /* if not found, create source with Group Timer: (A-X-Y)=Group Timer */
- long group_timer_msec;
- source = source_new(group, *src_addr);
- if (!source) {
- /* ugh, internal malloc failure, skip source */
- continue;
- }
-
- zassert(!source->t_source_timer); /* timer == 0 */
- group_timer_msec = igmp_group_timer_remain_msec(group);
- igmp_source_timer_on(group, source, group_timer_msec);
- zassert(source->t_source_timer); /* (A-X-Y) timer > 0 */
-
- /* make sure source is created with DELETE flag unset */
- zassert(!IGMP_SOURCE_TEST_DELETE(source->source_flags));
- }
-
- /* make sure reported source has DELETE flag unset */
- zassert(!IGMP_SOURCE_TEST_DELETE(source->source_flags));
-
- if (source->t_source_timer) {
- /* if source timer>0 mark SEND flag: Q(G,A-Y) */
- IGMP_SOURCE_DO_SEND(source->source_flags);
- ++num_sources_tosend;
- }
-
- } /* scan received sources (A) */
-
- /*
- delete all sources marked with DELETE flag:
- Delete (X-A)
- Delete (Y-A)
- */
- source_delete_by_flag(group->group_source_list);
-
- /* send sources marked with SEND flag: Q(G,A-Y) */
- if (num_sources_tosend > 0) {
- source_query_send_by_flag(group, num_sources_tosend);
- }
+ int num_sources_tosend = 0;
+ int i;
+
+ /* set DELETE flag for all known sources (X,Y) */
+ source_mark_delete_flag(group);
+
+ /* clear off SEND flag from all known sources (X,Y) */
+ source_clear_send_flag(group->group_source_list);
+
+ if (num_sources == 0) {
+ struct igmp_source *source;
+ struct in_addr any = {.s_addr = INADDR_ANY};
+
+ source = igmp_find_source_by_addr(group, any);
+ if (source)
+ IGMP_SOURCE_DONT_DELETE(source->source_flags);
+ }
+
+ /* scan received sources (A) */
+ for (i = 0; i < num_sources; ++i) {
+ struct igmp_source *source;
+ struct in_addr *src_addr;
+
+ src_addr = sources + i;
+
+ /* lookup reported source (A) in known sources (X,Y) */
+ source = igmp_find_source_by_addr(group, *src_addr);
+ if (source) {
+ /* if found, clear off DELETE flag from reported source
+ * (A) */
+ IGMP_SOURCE_DONT_DELETE(source->source_flags);
+ } else {
+ /* if not found, create source with Group Timer:
+ * (A-X-Y)=Group Timer */
+ long group_timer_msec;
+ source = source_new(group, *src_addr);
+ if (!source) {
+ /* ugh, internal malloc failure, skip source */
+ continue;
+ }
+
+ zassert(!source->t_source_timer); /* timer == 0 */
+ group_timer_msec = igmp_group_timer_remain_msec(group);
+ igmp_source_timer_on(group, source, group_timer_msec);
+ zassert(source->t_source_timer); /* (A-X-Y) timer > 0 */
+
+ /* make sure source is created with DELETE flag unset */
+ zassert(!IGMP_SOURCE_TEST_DELETE(source->source_flags));
+ }
+
+ /* make sure reported source has DELETE flag unset */
+ zassert(!IGMP_SOURCE_TEST_DELETE(source->source_flags));
+
+ if (source->t_source_timer) {
+ /* if source timer>0 mark SEND flag: Q(G,A-Y) */
+ IGMP_SOURCE_DO_SEND(source->source_flags);
+ ++num_sources_tosend;
+ }
+
+ } /* scan received sources (A) */
+
+ /*
+ delete all sources marked with DELETE flag:
+ Delete (X-A)
+ Delete (Y-A)
+ */
+ source_delete_by_flag(group->group_source_list);
+
+ /* send sources marked with SEND flag: Q(G,A-Y) */
+ if (num_sources_tosend > 0) {
+ source_query_send_by_flag(group, num_sources_tosend);
+ }
}
void igmpv3_report_toex(struct igmp_sock *igmp, struct in_addr from,
- struct in_addr group_addr,
- int num_sources, struct in_addr *sources)
+ struct in_addr group_addr, int num_sources,
+ struct in_addr *sources)
{
- struct interface *ifp = igmp->interface;
- struct igmp_group *group;
-
- on_trace(__PRETTY_FUNCTION__,
- ifp, from, group_addr, num_sources, sources);
-
- /* non-existant group is created as INCLUDE {empty} */
- group = igmp_add_group_by_addr(igmp, group_addr);
- if (!group) {
- return;
- }
-
- if (group->group_filtermode_isexcl) {
- /* EXCLUDE mode */
- toex_excl(group, num_sources, sources);
- }
- else {
- /* INCLUDE mode */
- toex_incl(group, num_sources, sources);
- zassert(group->group_filtermode_isexcl);
- }
- zassert(group->group_filtermode_isexcl);
-
- /* Group Timer=GMI */
- igmp_group_reset_gmi(group);
+ struct interface *ifp = igmp->interface;
+ struct igmp_group *group;
+
+ on_trace(__PRETTY_FUNCTION__, ifp, from, group_addr, num_sources,
+ sources);
+
+ /* non-existant group is created as INCLUDE {empty} */
+ group = igmp_add_group_by_addr(igmp, group_addr);
+ if (!group) {
+ return;
+ }
+
+ if (group->group_filtermode_isexcl) {
+ /* EXCLUDE mode */
+ toex_excl(group, num_sources, sources);
+ } else {
+ /* INCLUDE mode */
+ toex_incl(group, num_sources, sources);
+ zassert(group->group_filtermode_isexcl);
+ }
+ zassert(group->group_filtermode_isexcl);
+
+ /* Group Timer=GMI */
+ igmp_group_reset_gmi(group);
}
void igmpv3_report_allow(struct igmp_sock *igmp, struct in_addr from,
- struct in_addr group_addr,
- int num_sources, struct in_addr *sources)
+ struct in_addr group_addr, int num_sources,
+ struct in_addr *sources)
{
- on_trace(__PRETTY_FUNCTION__,
- igmp->interface, from, group_addr, num_sources, sources);
+ on_trace(__PRETTY_FUNCTION__, igmp->interface, from, group_addr,
+ num_sources, sources);
- allow(igmp, from, group_addr, num_sources, sources);
+ allow(igmp, from, group_addr, num_sources, sources);
}
/*
@@ -1005,67 +1003,64 @@ void igmpv3_report_allow(struct igmp_sock *igmp, struct in_addr from,
*/
static void group_retransmit_group(struct igmp_group *group)
{
- struct igmp_sock *igmp;
- struct pim_interface *pim_ifp;
- long lmqc; /* Last Member Query Count */
- long lmqi_msec; /* Last Member Query Interval */
- long lmqt_msec; /* Last Member Query Time */
- int s_flag;
- int query_buf_size;
-
- igmp = group->group_igmp_sock;
- pim_ifp = igmp->interface->info;
-
- if (pim_ifp->igmp_version == 3) {
- query_buf_size = PIM_IGMP_BUFSIZE_WRITE;
- } else {
- query_buf_size = IGMP_V12_MSG_SIZE;
- }
-
- char query_buf[query_buf_size];
-
- lmqc = igmp->querier_robustness_variable;
- lmqi_msec = 100 * pim_ifp->igmp_specific_query_max_response_time_dsec;
- lmqt_msec = lmqc * lmqi_msec;
-
- /*
- RFC3376: 6.6.3.1. Building and Sending Group Specific Queries
-
- When transmitting a group specific query, if the group timer is
- larger than LMQT, the "Suppress Router-Side Processing" bit is set
- in the query message.
- */
- s_flag = igmp_group_timer_remain_msec(group) > lmqt_msec;
-
- if (PIM_DEBUG_IGMP_TRACE) {
- char group_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
- zlog_debug("retransmit_group_specific_query: group %s on %s: s_flag=%d count=%d",
- group_str, igmp->interface->name, s_flag,
- group->group_specific_query_retransmit_count);
- }
-
- /*
- RFC3376: 4.1.12. IP Destination Addresses for Queries
-
- Group-Specific and Group-and-Source-Specific Queries are sent with
- an IP destination address equal to the multicast address of
- interest.
- */
-
- igmp_send_query(pim_ifp->igmp_version,
- group,
- igmp->fd,
- igmp->interface->name,
- query_buf,
- sizeof(query_buf),
- 0 /* num_sources_tosend */,
- group->group_addr /* dst_addr */,
- group->group_addr /* group_addr */,
- pim_ifp->igmp_specific_query_max_response_time_dsec,
- s_flag,
- igmp->querier_robustness_variable,
- igmp->querier_query_interval);
+ struct igmp_sock *igmp;
+ struct pim_interface *pim_ifp;
+ long lmqc; /* Last Member Query Count */
+ long lmqi_msec; /* Last Member Query Interval */
+ long lmqt_msec; /* Last Member Query Time */
+ int s_flag;
+ int query_buf_size;
+
+ igmp = group->group_igmp_sock;
+ pim_ifp = igmp->interface->info;
+
+ if (pim_ifp->igmp_version == 3) {
+ query_buf_size = PIM_IGMP_BUFSIZE_WRITE;
+ } else {
+ query_buf_size = IGMP_V12_MSG_SIZE;
+ }
+
+ char query_buf[query_buf_size];
+
+ lmqc = igmp->querier_robustness_variable;
+ lmqi_msec = 100 * pim_ifp->igmp_specific_query_max_response_time_dsec;
+ lmqt_msec = lmqc * lmqi_msec;
+
+ /*
+ RFC3376: 6.6.3.1. Building and Sending Group Specific Queries
+
+ When transmitting a group specific query, if the group timer is
+ larger than LMQT, the "Suppress Router-Side Processing" bit is set
+ in the query message.
+ */
+ s_flag = igmp_group_timer_remain_msec(group) > lmqt_msec;
+
+ if (PIM_DEBUG_IGMP_TRACE) {
+ char group_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<group?>", group->group_addr, group_str,
+ sizeof(group_str));
+ zlog_debug(
+ "retransmit_group_specific_query: group %s on %s: s_flag=%d count=%d",
+ group_str, igmp->interface->name, s_flag,
+ group->group_specific_query_retransmit_count);
+ }
+
+ /*
+ RFC3376: 4.1.12. IP Destination Addresses for Queries
+
+ Group-Specific and Group-and-Source-Specific Queries are sent with
+ an IP destination address equal to the multicast address of
+ interest.
+ */
+
+ igmp_send_query(pim_ifp->igmp_version, group, igmp->fd,
+ igmp->interface->name, query_buf, sizeof(query_buf),
+ 0 /* num_sources_tosend */,
+ group->group_addr /* dst_addr */,
+ group->group_addr /* group_addr */,
+ pim_ifp->igmp_specific_query_max_response_time_dsec,
+ s_flag, igmp->querier_robustness_variable,
+ igmp->querier_query_interval);
}
/*
@@ -1083,205 +1078,214 @@ static void group_retransmit_group(struct igmp_group *group)
static int group_retransmit_sources(struct igmp_group *group,
int send_with_sflag_set)
{
- struct igmp_sock *igmp;
- struct pim_interface *pim_ifp;
- long lmqc; /* Last Member Query Count */
- long lmqi_msec; /* Last Member Query Interval */
- long lmqt_msec; /* Last Member Query Time */
- char query_buf1[PIM_IGMP_BUFSIZE_WRITE]; /* 1 = with s_flag set */
- char query_buf2[PIM_IGMP_BUFSIZE_WRITE]; /* 2 = with s_flag clear */
- int query_buf1_max_sources;
- int query_buf2_max_sources;
- struct in_addr *source_addr1;
- struct in_addr *source_addr2;
- int num_sources_tosend1;
- int num_sources_tosend2;
- struct listnode *src_node;
- struct igmp_source *src;
- int num_retransmit_sources_left = 0;
-
- source_addr1 = (struct in_addr *)(query_buf1 + IGMP_V3_SOURCES_OFFSET);
- source_addr2 = (struct in_addr *)(query_buf2 + IGMP_V3_SOURCES_OFFSET);
-
- igmp = group->group_igmp_sock;
- pim_ifp = igmp->interface->info;
-
- lmqc = igmp->querier_robustness_variable;
- lmqi_msec = 100 * pim_ifp->igmp_specific_query_max_response_time_dsec;
- lmqt_msec = lmqc * lmqi_msec;
-
- /* Scan all group sources */
- for (ALL_LIST_ELEMENTS_RO(group->group_source_list, src_node, src)) {
-
- /* Source has retransmission state? */
- if (src->source_query_retransmit_count < 1)
- continue;
-
- if (--src->source_query_retransmit_count > 0) {
- ++num_retransmit_sources_left;
- }
-
- /* Copy source address into appropriate query buffer */
- if (igmp_source_timer_remain_msec(src) > lmqt_msec) {
- *source_addr1 = src->source_addr;
- ++source_addr1;
- }
- else {
- *source_addr2 = src->source_addr;
- ++source_addr2;
- }
-
- }
-
- num_sources_tosend1 = source_addr1 - (struct in_addr *)(query_buf1 + IGMP_V3_SOURCES_OFFSET);
- num_sources_tosend2 = source_addr2 - (struct in_addr *)(query_buf2 + IGMP_V3_SOURCES_OFFSET);
-
- if (PIM_DEBUG_IGMP_TRACE) {
- char group_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
- zlog_debug("retransmit_grp&src_specific_query: group %s on %s: srcs_with_sflag=%d srcs_wo_sflag=%d will_send_sflag=%d retransmit_src_left=%d",
- group_str, igmp->interface->name,
- num_sources_tosend1,
- num_sources_tosend2,
- send_with_sflag_set,
- num_retransmit_sources_left);
- }
-
- if (num_sources_tosend1 > 0) {
- /*
- Send group-and-source-specific query with s_flag set and all
- sources with timers greater than LMQT.
- */
-
- if (send_with_sflag_set) {
-
- query_buf1_max_sources = (sizeof(query_buf1) - IGMP_V3_SOURCES_OFFSET) >> 2;
- if (num_sources_tosend1 > query_buf1_max_sources) {
- char group_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
- zlog_warn("%s: group %s on %s: s_flag=1 unable to fit %d sources into buf_size=%zu (max_sources=%d)",
- __PRETTY_FUNCTION__, group_str, igmp->interface->name,
- num_sources_tosend1, sizeof(query_buf1), query_buf1_max_sources);
- }
- else {
- /*
- RFC3376: 4.1.12. IP Destination Addresses for Queries
-
- Group-Specific and Group-and-Source-Specific Queries are sent with
- an IP destination address equal to the multicast address of
- interest.
- */
-
- igmp_send_query(pim_ifp->igmp_version,
- group,
- igmp->fd,
- igmp->interface->name,
- query_buf1,
- sizeof(query_buf1),
- num_sources_tosend1,
- group->group_addr,
- group->group_addr,
- pim_ifp->igmp_specific_query_max_response_time_dsec,
- 1 /* s_flag */,
- igmp->querier_robustness_variable,
- igmp->querier_query_interval);
- }
-
- } /* send_with_sflag_set */
-
- }
-
- if (num_sources_tosend2 > 0) {
- /*
- Send group-and-source-specific query with s_flag clear and all
- sources with timers lower or equal to LMQT.
- */
-
- query_buf2_max_sources = (sizeof(query_buf2) - IGMP_V3_SOURCES_OFFSET) >> 2;
- if (num_sources_tosend2 > query_buf2_max_sources) {
- char group_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
- zlog_warn("%s: group %s on %s: s_flag=0 unable to fit %d sources into buf_size=%zu (max_sources=%d)",
- __PRETTY_FUNCTION__, group_str, igmp->interface->name,
- num_sources_tosend2, sizeof(query_buf2), query_buf2_max_sources);
- }
- else {
- /*
- RFC3376: 4.1.12. IP Destination Addresses for Queries
-
- Group-Specific and Group-and-Source-Specific Queries are sent with
- an IP destination address equal to the multicast address of
- interest.
- */
-
- igmp_send_query(pim_ifp->igmp_version,
- group,
- igmp->fd,
- igmp->interface->name,
- query_buf2,
- sizeof(query_buf2),
- num_sources_tosend2,
- group->group_addr,
- group->group_addr,
- pim_ifp->igmp_specific_query_max_response_time_dsec,
- 0 /* s_flag */,
- igmp->querier_robustness_variable,
- igmp->querier_query_interval);
- }
- }
-
- return num_retransmit_sources_left;
+ struct igmp_sock *igmp;
+ struct pim_interface *pim_ifp;
+ long lmqc; /* Last Member Query Count */
+ long lmqi_msec; /* Last Member Query Interval */
+ long lmqt_msec; /* Last Member Query Time */
+ char query_buf1[PIM_IGMP_BUFSIZE_WRITE]; /* 1 = with s_flag set */
+ char query_buf2[PIM_IGMP_BUFSIZE_WRITE]; /* 2 = with s_flag clear */
+ int query_buf1_max_sources;
+ int query_buf2_max_sources;
+ struct in_addr *source_addr1;
+ struct in_addr *source_addr2;
+ int num_sources_tosend1;
+ int num_sources_tosend2;
+ struct listnode *src_node;
+ struct igmp_source *src;
+ int num_retransmit_sources_left = 0;
+
+ source_addr1 = (struct in_addr *)(query_buf1 + IGMP_V3_SOURCES_OFFSET);
+ source_addr2 = (struct in_addr *)(query_buf2 + IGMP_V3_SOURCES_OFFSET);
+
+ igmp = group->group_igmp_sock;
+ pim_ifp = igmp->interface->info;
+
+ lmqc = igmp->querier_robustness_variable;
+ lmqi_msec = 100 * pim_ifp->igmp_specific_query_max_response_time_dsec;
+ lmqt_msec = lmqc * lmqi_msec;
+
+ /* Scan all group sources */
+ for (ALL_LIST_ELEMENTS_RO(group->group_source_list, src_node, src)) {
+
+ /* Source has retransmission state? */
+ if (src->source_query_retransmit_count < 1)
+ continue;
+
+ if (--src->source_query_retransmit_count > 0) {
+ ++num_retransmit_sources_left;
+ }
+
+ /* Copy source address into appropriate query buffer */
+ if (igmp_source_timer_remain_msec(src) > lmqt_msec) {
+ *source_addr1 = src->source_addr;
+ ++source_addr1;
+ } else {
+ *source_addr2 = src->source_addr;
+ ++source_addr2;
+ }
+ }
+
+ num_sources_tosend1 =
+ source_addr1
+ - (struct in_addr *)(query_buf1 + IGMP_V3_SOURCES_OFFSET);
+ num_sources_tosend2 =
+ source_addr2
+ - (struct in_addr *)(query_buf2 + IGMP_V3_SOURCES_OFFSET);
+
+ if (PIM_DEBUG_IGMP_TRACE) {
+ char group_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<group?>", group->group_addr, group_str,
+ sizeof(group_str));
+ zlog_debug(
+ "retransmit_grp&src_specific_query: group %s on %s: srcs_with_sflag=%d srcs_wo_sflag=%d will_send_sflag=%d retransmit_src_left=%d",
+ group_str, igmp->interface->name, num_sources_tosend1,
+ num_sources_tosend2, send_with_sflag_set,
+ num_retransmit_sources_left);
+ }
+
+ if (num_sources_tosend1 > 0) {
+ /*
+ Send group-and-source-specific query with s_flag set and all
+ sources with timers greater than LMQT.
+ */
+
+ if (send_with_sflag_set) {
+
+ query_buf1_max_sources =
+ (sizeof(query_buf1) - IGMP_V3_SOURCES_OFFSET)
+ >> 2;
+ if (num_sources_tosend1 > query_buf1_max_sources) {
+ char group_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<group?>", group->group_addr,
+ group_str, sizeof(group_str));
+ zlog_warn(
+ "%s: group %s on %s: s_flag=1 unable to fit %d sources into buf_size=%zu (max_sources=%d)",
+ __PRETTY_FUNCTION__, group_str,
+ igmp->interface->name,
+ num_sources_tosend1, sizeof(query_buf1),
+ query_buf1_max_sources);
+ } else {
+ /*
+ RFC3376: 4.1.12. IP Destination Addresses for
+ Queries
+
+ Group-Specific and Group-and-Source-Specific
+ Queries are sent with
+ an IP destination address equal to the
+ multicast address of
+ interest.
+ */
+
+ igmp_send_query(
+ pim_ifp->igmp_version, group, igmp->fd,
+ igmp->interface->name, query_buf1,
+ sizeof(query_buf1), num_sources_tosend1,
+ group->group_addr, group->group_addr,
+ pim_ifp->igmp_specific_query_max_response_time_dsec,
+ 1 /* s_flag */,
+ igmp->querier_robustness_variable,
+ igmp->querier_query_interval);
+ }
+
+ } /* send_with_sflag_set */
+ }
+
+ if (num_sources_tosend2 > 0) {
+ /*
+ Send group-and-source-specific query with s_flag clear and all
+ sources with timers lower or equal to LMQT.
+ */
+
+ query_buf2_max_sources =
+ (sizeof(query_buf2) - IGMP_V3_SOURCES_OFFSET) >> 2;
+ if (num_sources_tosend2 > query_buf2_max_sources) {
+ char group_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<group?>", group->group_addr, group_str,
+ sizeof(group_str));
+ zlog_warn(
+ "%s: group %s on %s: s_flag=0 unable to fit %d sources into buf_size=%zu (max_sources=%d)",
+ __PRETTY_FUNCTION__, group_str,
+ igmp->interface->name, num_sources_tosend2,
+ sizeof(query_buf2), query_buf2_max_sources);
+ } else {
+ /*
+ RFC3376: 4.1.12. IP Destination Addresses for Queries
+
+ Group-Specific and Group-and-Source-Specific Queries
+ are sent with
+ an IP destination address equal to the multicast
+ address of
+ interest.
+ */
+
+ igmp_send_query(
+ pim_ifp->igmp_version, group, igmp->fd,
+ igmp->interface->name, query_buf2,
+ sizeof(query_buf2), num_sources_tosend2,
+ group->group_addr, group->group_addr,
+ pim_ifp->igmp_specific_query_max_response_time_dsec,
+ 0 /* s_flag */,
+ igmp->querier_robustness_variable,
+ igmp->querier_query_interval);
+ }
+ }
+
+ return num_retransmit_sources_left;
}
static int igmp_group_retransmit(struct thread *t)
{
- struct igmp_group *group;
- int num_retransmit_sources_left;
- int send_with_sflag_set; /* boolean */
-
- group = THREAD_ARG(t);
-
- if (PIM_DEBUG_IGMP_TRACE) {
- char group_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
- zlog_debug("group_retransmit_timer: group %s on %s",
- group_str, group->group_igmp_sock->interface->name);
- }
-
- /* Retransmit group-specific queries? (RFC3376: 6.6.3.1) */
- if (group->group_specific_query_retransmit_count > 0) {
-
- /* Retransmit group-specific queries (RFC3376: 6.6.3.1) */
- group_retransmit_group(group);
- --group->group_specific_query_retransmit_count;
-
- /*
- RFC3376: 6.6.3.2
- If a group specific query is scheduled to be transmitted at the
- same time as a group and source specific query for the same group,
- then transmission of the group and source specific message with the
- "Suppress Router-Side Processing" bit set may be suppressed.
- */
- send_with_sflag_set = 0; /* boolean=false */
- }
- else {
- send_with_sflag_set = 1; /* boolean=true */
- }
-
- /* Retransmit group-and-source-specific queries (RFC3376: 6.6.3.2) */
- num_retransmit_sources_left = group_retransmit_sources(group,
- send_with_sflag_set);
-
- /*
- Keep group retransmit timer running if there is any retransmit
- counter pending
- */
- if ((num_retransmit_sources_left > 0) ||
- (group->group_specific_query_retransmit_count > 0)) {
- group_retransmit_timer_on(group);
- }
-
- return 0;
+ struct igmp_group *group;
+ int num_retransmit_sources_left;
+ int send_with_sflag_set; /* boolean */
+
+ group = THREAD_ARG(t);
+
+ if (PIM_DEBUG_IGMP_TRACE) {
+ char group_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<group?>", group->group_addr, group_str,
+ sizeof(group_str));
+ zlog_debug("group_retransmit_timer: group %s on %s", group_str,
+ group->group_igmp_sock->interface->name);
+ }
+
+ /* Retransmit group-specific queries? (RFC3376: 6.6.3.1) */
+ if (group->group_specific_query_retransmit_count > 0) {
+
+ /* Retransmit group-specific queries (RFC3376: 6.6.3.1) */
+ group_retransmit_group(group);
+ --group->group_specific_query_retransmit_count;
+
+ /*
+ RFC3376: 6.6.3.2
+ If a group specific query is scheduled to be transmitted at
+ the
+ same time as a group and source specific query for the same
+ group,
+ then transmission of the group and source specific message
+ with the
+ "Suppress Router-Side Processing" bit set may be suppressed.
+ */
+ send_with_sflag_set = 0; /* boolean=false */
+ } else {
+ send_with_sflag_set = 1; /* boolean=true */
+ }
+
+ /* Retransmit group-and-source-specific queries (RFC3376: 6.6.3.2) */
+ num_retransmit_sources_left =
+ group_retransmit_sources(group, send_with_sflag_set);
+
+ /*
+ Keep group retransmit timer running if there is any retransmit
+ counter pending
+ */
+ if ((num_retransmit_sources_left > 0)
+ || (group->group_specific_query_retransmit_count > 0)) {
+ group_retransmit_timer_on(group);
+ }
+
+ return 0;
}
/*
@@ -1291,42 +1295,42 @@ static int igmp_group_retransmit(struct thread *t)
*/
static void group_retransmit_timer_on(struct igmp_group *group)
{
- struct igmp_sock *igmp;
- struct pim_interface *pim_ifp;
- long lmqi_msec; /* Last Member Query Interval */
-
- /* if group retransmit timer is running, do nothing */
- if (group->t_group_query_retransmit_timer) {
- return;
- }
-
- igmp = group->group_igmp_sock;
- pim_ifp = igmp->interface->info;
-
- lmqi_msec = 100 * pim_ifp->igmp_specific_query_max_response_time_dsec;
-
- if (PIM_DEBUG_IGMP_TRACE) {
- char group_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
- zlog_debug("Scheduling %ld.%03ld sec retransmit timer for group %s on %s",
- lmqi_msec / 1000,
- lmqi_msec % 1000,
- group_str,
- igmp->interface->name);
- }
-
- thread_add_timer_msec(master, igmp_group_retransmit, group, lmqi_msec,
- &group->t_group_query_retransmit_timer);
+ struct igmp_sock *igmp;
+ struct pim_interface *pim_ifp;
+ long lmqi_msec; /* Last Member Query Interval */
+
+ /* if group retransmit timer is running, do nothing */
+ if (group->t_group_query_retransmit_timer) {
+ return;
+ }
+
+ igmp = group->group_igmp_sock;
+ pim_ifp = igmp->interface->info;
+
+ lmqi_msec = 100 * pim_ifp->igmp_specific_query_max_response_time_dsec;
+
+ if (PIM_DEBUG_IGMP_TRACE) {
+ char group_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<group?>", group->group_addr, group_str,
+ sizeof(group_str));
+ zlog_debug(
+ "Scheduling %ld.%03ld sec retransmit timer for group %s on %s",
+ lmqi_msec / 1000, lmqi_msec % 1000, group_str,
+ igmp->interface->name);
+ }
+
+ thread_add_timer_msec(master, igmp_group_retransmit, group, lmqi_msec,
+ &group->t_group_query_retransmit_timer);
}
static long igmp_group_timer_remain_msec(struct igmp_group *group)
{
- return pim_time_timer_remain_msec(group->t_group_timer);
+ return pim_time_timer_remain_msec(group->t_group_timer);
}
static long igmp_source_timer_remain_msec(struct igmp_source *source)
{
- return pim_time_timer_remain_msec(source->t_source_timer);
+ return pim_time_timer_remain_msec(source->t_source_timer);
}
/*
@@ -1334,21 +1338,22 @@ static long igmp_source_timer_remain_msec(struct igmp_source *source)
*/
static void group_query_send(struct igmp_group *group)
{
- long lmqc; /* Last Member Query Count */
+ long lmqc; /* Last Member Query Count */
- lmqc = group->group_igmp_sock->querier_robustness_variable;
+ lmqc = group->group_igmp_sock->querier_robustness_variable;
- /* lower group timer to lmqt */
- igmp_group_timer_lower_to_lmqt(group);
+ /* lower group timer to lmqt */
+ igmp_group_timer_lower_to_lmqt(group);
- /* reset retransmission counter */
- group->group_specific_query_retransmit_count = lmqc;
+ /* reset retransmission counter */
+ group->group_specific_query_retransmit_count = lmqc;
- /* immediately send group specific query (decrease retransmit counter by 1)*/
- group_retransmit_group(group);
+ /* immediately send group specific query (decrease retransmit counter by
+ * 1)*/
+ group_retransmit_group(group);
- /* make sure group retransmit timer is running */
- group_retransmit_timer_on(group);
+ /* make sure group retransmit timer is running */
+ group_retransmit_timer_on(group);
}
/*
@@ -1357,612 +1362,674 @@ static void group_query_send(struct igmp_group *group)
static void source_query_send_by_flag(struct igmp_group *group,
int num_sources_tosend)
{
- struct igmp_sock *igmp;
- struct pim_interface *pim_ifp;
- struct listnode *src_node;
- struct igmp_source *src;
- long lmqc; /* Last Member Query Count */
- long lmqi_msec; /* Last Member Query Interval */
- long lmqt_msec; /* Last Member Query Time */
-
- zassert(num_sources_tosend > 0);
-
- igmp = group->group_igmp_sock;
- pim_ifp = igmp->interface->info;
-
- lmqc = igmp->querier_robustness_variable;
- lmqi_msec = 100 * pim_ifp->igmp_specific_query_max_response_time_dsec;
- lmqt_msec = lmqc * lmqi_msec;
-
- /*
- RFC3376: 6.6.3.2. Building and Sending Group and Source Specific Queries
-
- (...) for each of the sources in X of group G, with source timer larger
- than LMQT:
- o Set number of retransmissions for each source to [Last Member
- Query Count].
- o Lower source timer to LMQT.
- */
- for (ALL_LIST_ELEMENTS_RO(group->group_source_list, src_node, src)) {
- if (IGMP_SOURCE_TEST_SEND(src->source_flags)) {
- /* source "src" in X of group G */
- if (igmp_source_timer_remain_msec(src) > lmqt_msec) {
- src->source_query_retransmit_count = lmqc;
- igmp_source_timer_lower_to_lmqt(src);
- }
- }
- }
-
- /* send group-and-source specific queries */
- group_retransmit_sources(group, 1 /* send_with_sflag_set=true */);
-
- /* make sure group retransmit timer is running */
- group_retransmit_timer_on(group);
+ struct igmp_sock *igmp;
+ struct pim_interface *pim_ifp;
+ struct listnode *src_node;
+ struct igmp_source *src;
+ long lmqc; /* Last Member Query Count */
+ long lmqi_msec; /* Last Member Query Interval */
+ long lmqt_msec; /* Last Member Query Time */
+
+ zassert(num_sources_tosend > 0);
+
+ igmp = group->group_igmp_sock;
+ pim_ifp = igmp->interface->info;
+
+ lmqc = igmp->querier_robustness_variable;
+ lmqi_msec = 100 * pim_ifp->igmp_specific_query_max_response_time_dsec;
+ lmqt_msec = lmqc * lmqi_msec;
+
+ /*
+ RFC3376: 6.6.3.2. Building and Sending Group and Source Specific
+ Queries
+
+ (...) for each of the sources in X of group G, with source timer
+ larger
+ than LMQT:
+ o Set number of retransmissions for each source to [Last Member
+ Query Count].
+ o Lower source timer to LMQT.
+ */
+ for (ALL_LIST_ELEMENTS_RO(group->group_source_list, src_node, src)) {
+ if (IGMP_SOURCE_TEST_SEND(src->source_flags)) {
+ /* source "src" in X of group G */
+ if (igmp_source_timer_remain_msec(src) > lmqt_msec) {
+ src->source_query_retransmit_count = lmqc;
+ igmp_source_timer_lower_to_lmqt(src);
+ }
+ }
+ }
+
+ /* send group-and-source specific queries */
+ group_retransmit_sources(group, 1 /* send_with_sflag_set=true */);
+
+ /* make sure group retransmit timer is running */
+ group_retransmit_timer_on(group);
}
-static void block_excl(struct igmp_group *group,
- int num_sources, struct in_addr *sources)
+static void block_excl(struct igmp_group *group, int num_sources,
+ struct in_addr *sources)
{
- int num_sources_tosend = 0;
- int i;
-
- /* 1. clear off SEND flag from all known sources (X,Y) */
- source_clear_send_flag(group->group_source_list);
-
- /* 2. scan received sources (A) */
- for (i = 0; i < num_sources; ++i) {
- struct igmp_source *source;
- struct in_addr *src_addr;
-
- src_addr = sources + i;
-
- /* lookup reported source (A) in known sources (X,Y) */
- source = igmp_find_source_by_addr(group, *src_addr);
- if (!source) {
- /* 3: if not found, create source with Group Timer: (A-X-Y)=Group Timer */
- long group_timer_msec;
- source = source_new(group, *src_addr);
- if (!source) {
- /* ugh, internal malloc failure, skip source */
- continue;
- }
-
- zassert(!source->t_source_timer); /* timer == 0 */
- group_timer_msec = igmp_group_timer_remain_msec(group);
- igmp_source_timer_on(group, source, group_timer_msec);
- zassert(source->t_source_timer); /* (A-X-Y) timer > 0 */
- }
-
- if (source->t_source_timer) {
- /* 4. if source timer>0 mark SEND flag: Q(G,A-Y) */
- IGMP_SOURCE_DO_SEND(source->source_flags);
- ++num_sources_tosend;
- }
- }
-
- /* 5. send sources marked with SEND flag: Q(G,A-Y) */
- if (num_sources_tosend > 0) {
- source_query_send_by_flag(group, num_sources_tosend);
- }
+ int num_sources_tosend = 0;
+ int i;
+
+ /* 1. clear off SEND flag from all known sources (X,Y) */
+ source_clear_send_flag(group->group_source_list);
+
+ /* 2. scan received sources (A) */
+ for (i = 0; i < num_sources; ++i) {
+ struct igmp_source *source;
+ struct in_addr *src_addr;
+
+ src_addr = sources + i;
+
+ /* lookup reported source (A) in known sources (X,Y) */
+ source = igmp_find_source_by_addr(group, *src_addr);
+ if (!source) {
+ /* 3: if not found, create source with Group Timer:
+ * (A-X-Y)=Group Timer */
+ long group_timer_msec;
+ source = source_new(group, *src_addr);
+ if (!source) {
+ /* ugh, internal malloc failure, skip source */
+ continue;
+ }
+
+ zassert(!source->t_source_timer); /* timer == 0 */
+ group_timer_msec = igmp_group_timer_remain_msec(group);
+ igmp_source_timer_on(group, source, group_timer_msec);
+ zassert(source->t_source_timer); /* (A-X-Y) timer > 0 */
+ }
+
+ if (source->t_source_timer) {
+ /* 4. if source timer>0 mark SEND flag: Q(G,A-Y) */
+ IGMP_SOURCE_DO_SEND(source->source_flags);
+ ++num_sources_tosend;
+ }
+ }
+
+ /* 5. send sources marked with SEND flag: Q(G,A-Y) */
+ if (num_sources_tosend > 0) {
+ source_query_send_by_flag(group, num_sources_tosend);
+ }
}
-static void block_incl(struct igmp_group *group,
- int num_sources, struct in_addr *sources)
+static void block_incl(struct igmp_group *group, int num_sources,
+ struct in_addr *sources)
{
- int num_sources_tosend = 0;
- int i;
-
- /* 1. clear off SEND flag from all known sources (B) */
- source_clear_send_flag(group->group_source_list);
-
- /* 2. scan received sources (A) */
- for (i = 0; i < num_sources; ++i) {
- struct igmp_source *source;
- struct in_addr *src_addr;
-
- src_addr = sources + i;
-
- /* lookup reported source (A) in known sources (B) */
- source = igmp_find_source_by_addr(group, *src_addr);
- if (source) {
- /* 3. if found (A*B), mark SEND flag: Q(G,A*B) */
- IGMP_SOURCE_DO_SEND(source->source_flags);
- ++num_sources_tosend;
- }
- }
-
- /* 4. send sources marked with SEND flag: Q(G,A*B) */
- if (num_sources_tosend > 0) {
- source_query_send_by_flag(group, num_sources_tosend);
- }
+ int num_sources_tosend = 0;
+ int i;
+
+ /* 1. clear off SEND flag from all known sources (B) */
+ source_clear_send_flag(group->group_source_list);
+
+ /* 2. scan received sources (A) */
+ for (i = 0; i < num_sources; ++i) {
+ struct igmp_source *source;
+ struct in_addr *src_addr;
+
+ src_addr = sources + i;
+
+ /* lookup reported source (A) in known sources (B) */
+ source = igmp_find_source_by_addr(group, *src_addr);
+ if (source) {
+ /* 3. if found (A*B), mark SEND flag: Q(G,A*B) */
+ IGMP_SOURCE_DO_SEND(source->source_flags);
+ ++num_sources_tosend;
+ }
+ }
+
+ /* 4. send sources marked with SEND flag: Q(G,A*B) */
+ if (num_sources_tosend > 0) {
+ source_query_send_by_flag(group, num_sources_tosend);
+ }
}
void igmpv3_report_block(struct igmp_sock *igmp, struct in_addr from,
- struct in_addr group_addr,
- int num_sources, struct in_addr *sources)
+ struct in_addr group_addr, int num_sources,
+ struct in_addr *sources)
{
- struct interface *ifp = igmp->interface;
- struct igmp_group *group;
-
- on_trace(__PRETTY_FUNCTION__,
- ifp, from, group_addr, num_sources, sources);
-
- /* non-existant group is created as INCLUDE {empty} */
- group = igmp_add_group_by_addr(igmp, group_addr);
- if (!group) {
- return;
- }
-
- if (group->group_filtermode_isexcl) {
- /* EXCLUDE mode */
- block_excl(group, num_sources, sources);
- }
- else {
- /* INCLUDE mode */
- block_incl(group, num_sources, sources);
- }
+ struct interface *ifp = igmp->interface;
+ struct igmp_group *group;
+
+ on_trace(__PRETTY_FUNCTION__, ifp, from, group_addr, num_sources,
+ sources);
+
+ /* non-existant group is created as INCLUDE {empty} */
+ group = igmp_add_group_by_addr(igmp, group_addr);
+ if (!group) {
+ return;
+ }
+
+ if (group->group_filtermode_isexcl) {
+ /* EXCLUDE mode */
+ block_excl(group, num_sources, sources);
+ } else {
+ /* INCLUDE mode */
+ block_incl(group, num_sources, sources);
+ }
}
void igmp_group_timer_lower_to_lmqt(struct igmp_group *group)
{
- struct igmp_sock *igmp;
- struct interface *ifp;
- struct pim_interface *pim_ifp;
- char *ifname;
- int lmqi_dsec; /* Last Member Query Interval */
- int lmqc; /* Last Member Query Count */
- int lmqt_msec; /* Last Member Query Time */
-
- /*
- RFC 3376: 6.2.2. Definition of Group Timers
-
- The group timer is only used when a group is in EXCLUDE mode and
- it represents the time for the *filter-mode* of the group to
- expire and switch to INCLUDE mode.
- */
- if (!group->group_filtermode_isexcl) {
- return;
- }
-
- igmp = group->group_igmp_sock;
- ifp = igmp->interface;
- pim_ifp = ifp->info;
- ifname = ifp->name;
-
- lmqi_dsec = pim_ifp->igmp_specific_query_max_response_time_dsec;
- lmqc = igmp->querier_robustness_variable;
- lmqt_msec = PIM_IGMP_LMQT_MSEC(lmqi_dsec, lmqc); /* lmqt_msec = (100 * lmqi_dsec) * lmqc */
-
- if (PIM_DEBUG_IGMP_TRACE) {
- char group_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
- zlog_debug("%s: group %s on %s: LMQC=%d LMQI=%d dsec LMQT=%d msec",
- __PRETTY_FUNCTION__,
- group_str, ifname,
- lmqc, lmqi_dsec, lmqt_msec);
- }
-
- zassert(group->group_filtermode_isexcl);
-
- igmp_group_timer_on(group, lmqt_msec, ifname);
+ struct igmp_sock *igmp;
+ struct interface *ifp;
+ struct pim_interface *pim_ifp;
+ char *ifname;
+ int lmqi_dsec; /* Last Member Query Interval */
+ int lmqc; /* Last Member Query Count */
+ int lmqt_msec; /* Last Member Query Time */
+
+ /*
+ RFC 3376: 6.2.2. Definition of Group Timers
+
+ The group timer is only used when a group is in EXCLUDE mode and
+ it represents the time for the *filter-mode* of the group to
+ expire and switch to INCLUDE mode.
+ */
+ if (!group->group_filtermode_isexcl) {
+ return;
+ }
+
+ igmp = group->group_igmp_sock;
+ ifp = igmp->interface;
+ pim_ifp = ifp->info;
+ ifname = ifp->name;
+
+ lmqi_dsec = pim_ifp->igmp_specific_query_max_response_time_dsec;
+ lmqc = igmp->querier_robustness_variable;
+ lmqt_msec = PIM_IGMP_LMQT_MSEC(
+ lmqi_dsec, lmqc); /* lmqt_msec = (100 * lmqi_dsec) * lmqc */
+
+ if (PIM_DEBUG_IGMP_TRACE) {
+ char group_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<group?>", group->group_addr, group_str,
+ sizeof(group_str));
+ zlog_debug(
+ "%s: group %s on %s: LMQC=%d LMQI=%d dsec LMQT=%d msec",
+ __PRETTY_FUNCTION__, group_str, ifname, lmqc, lmqi_dsec,
+ lmqt_msec);
+ }
+
+ zassert(group->group_filtermode_isexcl);
+
+ igmp_group_timer_on(group, lmqt_msec, ifname);
}
void igmp_source_timer_lower_to_lmqt(struct igmp_source *source)
{
- struct igmp_group *group;
- struct igmp_sock *igmp;
- struct interface *ifp;
- struct pim_interface *pim_ifp;
- char *ifname;
- int lmqi_dsec; /* Last Member Query Interval */
- int lmqc; /* Last Member Query Count */
- int lmqt_msec; /* Last Member Query Time */
-
- group = source->source_group;
- igmp = group->group_igmp_sock;
- ifp = igmp->interface;
- pim_ifp = ifp->info;
- ifname = ifp->name;
-
- lmqi_dsec = pim_ifp->igmp_specific_query_max_response_time_dsec;
- lmqc = igmp->querier_robustness_variable;
- lmqt_msec = PIM_IGMP_LMQT_MSEC(lmqi_dsec, lmqc); /* lmqt_msec = (100 * lmqi_dsec) * lmqc */
-
- if (PIM_DEBUG_IGMP_TRACE) {
- char group_str[INET_ADDRSTRLEN];
- char source_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<group?>", group->group_addr, group_str, sizeof(group_str));
- pim_inet4_dump("<source?>", source->source_addr, source_str, sizeof(source_str));
- zlog_debug("%s: group %s source %s on %s: LMQC=%d LMQI=%d dsec LMQT=%d msec",
- __PRETTY_FUNCTION__,
- group_str, source_str, ifname,
- lmqc, lmqi_dsec, lmqt_msec);
- }
-
- igmp_source_timer_on(group, source, lmqt_msec);
+ struct igmp_group *group;
+ struct igmp_sock *igmp;
+ struct interface *ifp;
+ struct pim_interface *pim_ifp;
+ char *ifname;
+ int lmqi_dsec; /* Last Member Query Interval */
+ int lmqc; /* Last Member Query Count */
+ int lmqt_msec; /* Last Member Query Time */
+
+ group = source->source_group;
+ igmp = group->group_igmp_sock;
+ ifp = igmp->interface;
+ pim_ifp = ifp->info;
+ ifname = ifp->name;
+
+ lmqi_dsec = pim_ifp->igmp_specific_query_max_response_time_dsec;
+ lmqc = igmp->querier_robustness_variable;
+ lmqt_msec = PIM_IGMP_LMQT_MSEC(
+ lmqi_dsec, lmqc); /* lmqt_msec = (100 * lmqi_dsec) * lmqc */
+
+ if (PIM_DEBUG_IGMP_TRACE) {
+ char group_str[INET_ADDRSTRLEN];
+ char source_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<group?>", group->group_addr, group_str,
+ sizeof(group_str));
+ pim_inet4_dump("<source?>", source->source_addr, source_str,
+ sizeof(source_str));
+ zlog_debug(
+ "%s: group %s source %s on %s: LMQC=%d LMQI=%d dsec LMQT=%d msec",
+ __PRETTY_FUNCTION__, group_str, source_str, ifname,
+ lmqc, lmqi_dsec, lmqt_msec);
+ }
+
+ igmp_source_timer_on(group, source, lmqt_msec);
}
-void
-igmp_v3_send_query (struct igmp_group *group,
- int fd,
- const char *ifname,
- char *query_buf,
- int query_buf_size,
- int num_sources,
- struct in_addr dst_addr,
- struct in_addr group_addr,
- int query_max_response_time_dsec,
- uint8_t s_flag,
- uint8_t querier_robustness_variable,
- uint16_t querier_query_interval)
+void igmp_v3_send_query(struct igmp_group *group, int fd, const char *ifname,
+ char *query_buf, int query_buf_size, int num_sources,
+ struct in_addr dst_addr, struct in_addr group_addr,
+ int query_max_response_time_dsec, uint8_t s_flag,
+ uint8_t querier_robustness_variable,
+ uint16_t querier_query_interval)
{
- ssize_t msg_size;
- uint8_t max_resp_code;
- uint8_t qqic;
- ssize_t sent;
- struct sockaddr_in to;
- socklen_t tolen;
- uint16_t checksum;
-
- zassert(num_sources >= 0);
-
- msg_size = IGMP_V3_SOURCES_OFFSET + (num_sources << 2);
- if (msg_size > query_buf_size) {
- zlog_err("%s %s: unable to send: msg_size=%zd larger than query_buf_size=%d",
- __FILE__, __PRETTY_FUNCTION__,
- msg_size, query_buf_size);
- return;
- }
-
- s_flag = PIM_FORCE_BOOLEAN(s_flag);
- zassert((s_flag == 0) || (s_flag == 1));
-
- max_resp_code = igmp_msg_encode16to8(query_max_response_time_dsec);
- qqic = igmp_msg_encode16to8(querier_query_interval);
-
- /*
- RFC 3376: 4.1.6. QRV (Querier's Robustness Variable)
-
- If non-zero, the QRV field contains the [Robustness Variable]
- value used by the querier, i.e., the sender of the Query. If the
- querier's [Robustness Variable] exceeds 7, the maximum value of
- the QRV field, the QRV is set to zero.
- */
- if (querier_robustness_variable > 7) {
- querier_robustness_variable = 0;
- }
-
- query_buf[0] = PIM_IGMP_MEMBERSHIP_QUERY;
- query_buf[1] = max_resp_code;
- *(uint16_t *)(query_buf + IGMP_CHECKSUM_OFFSET) = 0; /* for computing checksum */
- memcpy(query_buf+4, &group_addr, sizeof(struct in_addr));
-
- query_buf[8] = (s_flag << 3) | querier_robustness_variable;
- query_buf[9] = qqic;
- *(uint16_t *)(query_buf + IGMP_V3_NUMSOURCES_OFFSET) = htons(num_sources);
-
- checksum = in_cksum(query_buf, msg_size);
- *(uint16_t *)(query_buf + IGMP_CHECKSUM_OFFSET) = checksum;
-
- if (PIM_DEBUG_IGMP_PACKETS) {
- char dst_str[INET_ADDRSTRLEN];
- char group_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<dst?>", dst_addr, dst_str, sizeof(dst_str));
- pim_inet4_dump("<group?>", group_addr, group_str, sizeof(group_str));
- zlog_debug("Send IGMPv3 query to %s on %s for group %s, sources=%d msg_size=%zd s_flag=%x QRV=%u QQI=%u QQIC=%02x",
- dst_str, ifname, group_str,
- num_sources, msg_size, s_flag, querier_robustness_variable,
- querier_query_interval, qqic);
- }
-
- memset(&to, 0, sizeof(to));
- to.sin_family = AF_INET;
- to.sin_addr = dst_addr;
- tolen = sizeof(to);
-
- sent = sendto(fd, query_buf, msg_size, MSG_DONTWAIT,
- (struct sockaddr *)&to, tolen);
- if (sent != (ssize_t) msg_size) {
- char dst_str[INET_ADDRSTRLEN];
- char group_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<dst?>", dst_addr, dst_str, sizeof(dst_str));
- pim_inet4_dump("<group?>", group_addr, group_str, sizeof(group_str));
- if (sent < 0) {
- zlog_warn("Send IGMPv3 query failed due to %s on %s: group=%s msg_size=%zd: errno=%d: %s",
- dst_str, ifname, group_str, msg_size, errno, safe_strerror(errno));
- }
- else {
- zlog_warn("Send IGMPv3 query failed due to %s on %s: group=%s msg_size=%zd: sent=%zd",
- dst_str, ifname, group_str, msg_size, sent);
- }
- return;
- }
-
- /*
- s_flag sanity test: s_flag must be set for general queries
-
- RFC 3376: 6.6.1. Timer Updates
-
- When a router sends or receives a query with a clear Suppress
- Router-Side Processing flag, it must update its timers to reflect
- the correct timeout values for the group or sources being queried.
-
- General queries don't trigger timer update.
- */
- if (!s_flag) {
- /* general query? */
- if (PIM_INADDR_IS_ANY(group_addr)) {
- char dst_str[INET_ADDRSTRLEN];
- char group_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<dst?>", dst_addr, dst_str, sizeof(dst_str));
- pim_inet4_dump("<group?>", group_addr, group_str, sizeof(group_str));
- zlog_warn("%s: to %s on %s: group=%s sources=%d: s_flag is clear for general query!",
- __PRETTY_FUNCTION__,
- dst_str, ifname, group_str, num_sources);
- }
- }
+ ssize_t msg_size;
+ uint8_t max_resp_code;
+ uint8_t qqic;
+ ssize_t sent;
+ struct sockaddr_in to;
+ socklen_t tolen;
+ uint16_t checksum;
+
+ zassert(num_sources >= 0);
+
+ msg_size = IGMP_V3_SOURCES_OFFSET + (num_sources << 2);
+ if (msg_size > query_buf_size) {
+ zlog_err(
+ "%s %s: unable to send: msg_size=%zd larger than query_buf_size=%d",
+ __FILE__, __PRETTY_FUNCTION__, msg_size,
+ query_buf_size);
+ return;
+ }
+
+ s_flag = PIM_FORCE_BOOLEAN(s_flag);
+ zassert((s_flag == 0) || (s_flag == 1));
+
+ max_resp_code = igmp_msg_encode16to8(query_max_response_time_dsec);
+ qqic = igmp_msg_encode16to8(querier_query_interval);
+
+ /*
+ RFC 3376: 4.1.6. QRV (Querier's Robustness Variable)
+
+ If non-zero, the QRV field contains the [Robustness Variable]
+ value used by the querier, i.e., the sender of the Query. If the
+ querier's [Robustness Variable] exceeds 7, the maximum value of
+ the QRV field, the QRV is set to zero.
+ */
+ if (querier_robustness_variable > 7) {
+ querier_robustness_variable = 0;
+ }
+
+ query_buf[0] = PIM_IGMP_MEMBERSHIP_QUERY;
+ query_buf[1] = max_resp_code;
+ *(uint16_t *)(query_buf + IGMP_CHECKSUM_OFFSET) =
+ 0; /* for computing checksum */
+ memcpy(query_buf + 4, &group_addr, sizeof(struct in_addr));
+
+ query_buf[8] = (s_flag << 3) | querier_robustness_variable;
+ query_buf[9] = qqic;
+ *(uint16_t *)(query_buf + IGMP_V3_NUMSOURCES_OFFSET) =
+ htons(num_sources);
+
+ checksum = in_cksum(query_buf, msg_size);
+ *(uint16_t *)(query_buf + IGMP_CHECKSUM_OFFSET) = checksum;
+
+ if (PIM_DEBUG_IGMP_PACKETS) {
+ char dst_str[INET_ADDRSTRLEN];
+ char group_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<dst?>", dst_addr, dst_str, sizeof(dst_str));
+ pim_inet4_dump("<group?>", group_addr, group_str,
+ sizeof(group_str));
+ zlog_debug(
+ "Send IGMPv3 query to %s on %s for group %s, sources=%d msg_size=%zd s_flag=%x QRV=%u QQI=%u QQIC=%02x",
+ dst_str, ifname, group_str, num_sources, msg_size,
+ s_flag, querier_robustness_variable,
+ querier_query_interval, qqic);
+ }
+
+ memset(&to, 0, sizeof(to));
+ to.sin_family = AF_INET;
+ to.sin_addr = dst_addr;
+ tolen = sizeof(to);
+
+ sent = sendto(fd, query_buf, msg_size, MSG_DONTWAIT,
+ (struct sockaddr *)&to, tolen);
+ if (sent != (ssize_t)msg_size) {
+ char dst_str[INET_ADDRSTRLEN];
+ char group_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<dst?>", dst_addr, dst_str, sizeof(dst_str));
+ pim_inet4_dump("<group?>", group_addr, group_str,
+ sizeof(group_str));
+ if (sent < 0) {
+ zlog_warn(
+ "Send IGMPv3 query failed due to %s on %s: group=%s msg_size=%zd: errno=%d: %s",
+ dst_str, ifname, group_str, msg_size, errno,
+ safe_strerror(errno));
+ } else {
+ zlog_warn(
+ "Send IGMPv3 query failed due to %s on %s: group=%s msg_size=%zd: sent=%zd",
+ dst_str, ifname, group_str, msg_size, sent);
+ }
+ return;
+ }
+
+ /*
+ s_flag sanity test: s_flag must be set for general queries
+
+ RFC 3376: 6.6.1. Timer Updates
+
+ When a router sends or receives a query with a clear Suppress
+ Router-Side Processing flag, it must update its timers to reflect
+ the correct timeout values for the group or sources being queried.
+
+ General queries don't trigger timer update.
+ */
+ if (!s_flag) {
+ /* general query? */
+ if (PIM_INADDR_IS_ANY(group_addr)) {
+ char dst_str[INET_ADDRSTRLEN];
+ char group_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<dst?>", dst_addr, dst_str,
+ sizeof(dst_str));
+ pim_inet4_dump("<group?>", group_addr, group_str,
+ sizeof(group_str));
+ zlog_warn(
+ "%s: to %s on %s: group=%s sources=%d: s_flag is clear for general query!",
+ __PRETTY_FUNCTION__, dst_str, ifname, group_str,
+ num_sources);
+ }
+ }
}
-void
-igmp_v3_recv_query (struct igmp_sock *igmp, const char *from_str, char *igmp_msg)
+void igmp_v3_recv_query(struct igmp_sock *igmp, const char *from_str,
+ char *igmp_msg)
{
- struct interface *ifp;
- struct pim_interface *pim_ifp;
- struct in_addr group_addr;
- uint8_t resv_s_qrv = 0;
- uint8_t s_flag = 0;
- uint8_t qrv = 0;
- int i;
-
- memcpy(&group_addr, igmp_msg + 4, sizeof(struct in_addr));
- ifp = igmp->interface;
- pim_ifp = ifp->info;
-
- /*
- * RFC 3376: 4.1.6. QRV (Querier's Robustness Variable)
- *
- * Routers adopt the QRV value from the most recently received Query
- * as their own [Robustness Variable] value, unless that most
- * recently received QRV was zero, in which case the receivers use
- * the default [Robustness Variable] value specified in section 8.1
- * or a statically configured value.
- */
- resv_s_qrv = igmp_msg[8];
- qrv = 7 & resv_s_qrv;
- igmp->querier_robustness_variable = qrv ? qrv : pim_ifp->igmp_default_robustness_variable;
-
- /*
- * RFC 3376: 4.1.7. QQIC (Querier's Query Interval Code)
- *
- * Multicast routers that are not the current querier adopt the QQI
- * value from the most recently received Query as their own [Query
- * Interval] value, unless that most recently received QQI was zero,
- * in which case the receiving routers use the default.
- */
- if (igmp->t_other_querier_timer) {
- /* other querier present */
- uint8_t qqic;
- uint16_t qqi;
- qqic = igmp_msg[9];
- qqi = igmp_msg_decode8to16(qqic);
- igmp->querier_query_interval = qqi ? qqi : pim_ifp->igmp_default_query_interval;
-
- if (PIM_DEBUG_IGMP_TRACE) {
- char ifaddr_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str, sizeof(ifaddr_str));
- zlog_debug("Querier %s new query interval is %s QQI=%u sec (recv QQIC=%02x from %s)",
- ifaddr_str,
- qqi ? "recv-non-default" : "default",
- igmp->querier_query_interval,
- qqic,
- from_str);
- }
- }
-
- /*
- * RFC 3376: 6.6.1. Timer Updates
- *
- * When a router sends or receives a query with a clear Suppress
- * Router-Side Processing flag, it must update its timers to reflect
- * the correct timeout values for the group or sources being queried.
- *
- * General queries don't trigger timer update.
- */
- s_flag = (1 << 3) & resv_s_qrv;
-
- if (!s_flag) {
- /* s_flag is clear */
-
- if (PIM_INADDR_IS_ANY(group_addr)) {
- /* this is a general query */
- /* log that general query should have the s_flag set */
- zlog_warn("General IGMP query v3 from %s on %s: Suppress Router-Side Processing flag is clear",
- from_str, ifp->name);
- } else {
- struct igmp_group *group;
-
- /* this is a non-general query: perform timer updates */
-
- group = find_group_by_addr(igmp, group_addr);
- if (group) {
- int recv_num_sources = ntohs(*(uint16_t *)(igmp_msg + IGMP_V3_NUMSOURCES_OFFSET));
-
- /*
- * RFC 3376: 6.6.1. Timer Updates
- * Query Q(G,A): Source Timer for sources in A are lowered to LMQT
- * Query Q(G): Group Timer is lowered to LMQT
- */
- if (recv_num_sources < 1) {
- /* Query Q(G): Group Timer is lowered to LMQT */
-
- igmp_group_timer_lower_to_lmqt(group);
- } else {
- /* Query Q(G,A): Source Timer for sources in A are lowered to LMQT */
-
- /* Scan sources in query and lower their timers to LMQT */
- struct in_addr *sources = (struct in_addr *)(igmp_msg + IGMP_V3_SOURCES_OFFSET);
- for (i = 0; i < recv_num_sources; ++i) {
- struct in_addr src_addr;
- struct igmp_source *src;
- memcpy(&src_addr, sources + i, sizeof(struct in_addr));
- src = igmp_find_source_by_addr(group, src_addr);
- if (src) {
- igmp_source_timer_lower_to_lmqt(src);
- }
- }
- }
- } else {
- char group_str[INET_ADDRSTRLEN];
- pim_inet4_dump("<group?>", group_addr, group_str, sizeof(group_str));
- zlog_warn("IGMP query v3 from %s on %s: could not find group %s for timer update",
- from_str, ifp->name, group_str);
- }
- }
- } /* s_flag is clear: timer updates */
+ struct interface *ifp;
+ struct pim_interface *pim_ifp;
+ struct in_addr group_addr;
+ uint8_t resv_s_qrv = 0;
+ uint8_t s_flag = 0;
+ uint8_t qrv = 0;
+ int i;
+
+ memcpy(&group_addr, igmp_msg + 4, sizeof(struct in_addr));
+ ifp = igmp->interface;
+ pim_ifp = ifp->info;
+
+ /*
+ * RFC 3376: 4.1.6. QRV (Querier's Robustness Variable)
+ *
+ * Routers adopt the QRV value from the most recently received Query
+ * as their own [Robustness Variable] value, unless that most
+ * recently received QRV was zero, in which case the receivers use
+ * the default [Robustness Variable] value specified in section 8.1
+ * or a statically configured value.
+ */
+ resv_s_qrv = igmp_msg[8];
+ qrv = 7 & resv_s_qrv;
+ igmp->querier_robustness_variable =
+ qrv ? qrv : pim_ifp->igmp_default_robustness_variable;
+
+ /*
+ * RFC 3376: 4.1.7. QQIC (Querier's Query Interval Code)
+ *
+ * Multicast routers that are not the current querier adopt the QQI
+ * value from the most recently received Query as their own [Query
+ * Interval] value, unless that most recently received QQI was zero,
+ * in which case the receiving routers use the default.
+ */
+ if (igmp->t_other_querier_timer) {
+ /* other querier present */
+ uint8_t qqic;
+ uint16_t qqi;
+ qqic = igmp_msg[9];
+ qqi = igmp_msg_decode8to16(qqic);
+ igmp->querier_query_interval =
+ qqi ? qqi : pim_ifp->igmp_default_query_interval;
+
+ if (PIM_DEBUG_IGMP_TRACE) {
+ char ifaddr_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<ifaddr?>", igmp->ifaddr, ifaddr_str,
+ sizeof(ifaddr_str));
+ zlog_debug(
+ "Querier %s new query interval is %s QQI=%u sec (recv QQIC=%02x from %s)",
+ ifaddr_str,
+ qqi ? "recv-non-default" : "default",
+ igmp->querier_query_interval, qqic, from_str);
+ }
+ }
+
+ /*
+ * RFC 3376: 6.6.1. Timer Updates
+ *
+ * When a router sends or receives a query with a clear Suppress
+ * Router-Side Processing flag, it must update its timers to reflect
+ * the correct timeout values for the group or sources being queried.
+ *
+ * General queries don't trigger timer update.
+ */
+ s_flag = (1 << 3) & resv_s_qrv;
+
+ if (!s_flag) {
+ /* s_flag is clear */
+
+ if (PIM_INADDR_IS_ANY(group_addr)) {
+ /* this is a general query */
+ /* log that general query should have the s_flag set */
+ zlog_warn(
+ "General IGMP query v3 from %s on %s: Suppress Router-Side Processing flag is clear",
+ from_str, ifp->name);
+ } else {
+ struct igmp_group *group;
+
+ /* this is a non-general query: perform timer updates */
+
+ group = find_group_by_addr(igmp, group_addr);
+ if (group) {
+ int recv_num_sources = ntohs(*(
+ uint16_t
+ *)(igmp_msg
+ + IGMP_V3_NUMSOURCES_OFFSET));
+
+ /*
+ * RFC 3376: 6.6.1. Timer Updates
+ * Query Q(G,A): Source Timer for sources in A
+ * are lowered to LMQT
+ * Query Q(G): Group Timer is lowered to LMQT
+ */
+ if (recv_num_sources < 1) {
+ /* Query Q(G): Group Timer is lowered to
+ * LMQT */
+
+ igmp_group_timer_lower_to_lmqt(group);
+ } else {
+ /* Query Q(G,A): Source Timer for
+ * sources in A are lowered to LMQT */
+
+ /* Scan sources in query and lower their
+ * timers to LMQT */
+ struct in_addr *sources =
+ (struct in_addr
+ *)(igmp_msg
+ + IGMP_V3_SOURCES_OFFSET);
+ for (i = 0; i < recv_num_sources; ++i) {
+ struct in_addr src_addr;
+ struct igmp_source *src;
+ memcpy(&src_addr, sources + i,
+ sizeof(struct in_addr));
+ src = igmp_find_source_by_addr(
+ group, src_addr);
+ if (src) {
+ igmp_source_timer_lower_to_lmqt(
+ src);
+ }
+ }
+ }
+ } else {
+ char group_str[INET_ADDRSTRLEN];
+ pim_inet4_dump("<group?>", group_addr,
+ group_str, sizeof(group_str));
+ zlog_warn(
+ "IGMP query v3 from %s on %s: could not find group %s for timer update",
+ from_str, ifp->name, group_str);
+ }
+ }
+ } /* s_flag is clear: timer updates */
}
-int
-igmp_v3_recv_report (struct igmp_sock *igmp,
- struct in_addr from, const char *from_str,
- char *igmp_msg, int igmp_msg_len)
+int igmp_v3_recv_report(struct igmp_sock *igmp, struct in_addr from,
+ const char *from_str, char *igmp_msg, int igmp_msg_len)
{
- uint16_t recv_checksum;
- uint16_t checksum;
- int num_groups;
- uint8_t *group_record;
- uint8_t *report_pastend = (uint8_t *) igmp_msg + igmp_msg_len;
- struct interface *ifp = igmp->interface;
- int i;
- int local_ncb = 0;
-
- if (igmp_msg_len < IGMP_V3_MSG_MIN_SIZE) {
- zlog_warn("Recv IGMP report v3 from %s on %s: size=%d shorter than minimum=%d",
- from_str, ifp->name, igmp_msg_len, IGMP_V3_MSG_MIN_SIZE);
- return -1;
- }
-
- recv_checksum = *(uint16_t *) (igmp_msg + IGMP_CHECKSUM_OFFSET);
-
- /* for computing checksum */
- *(uint16_t *) (igmp_msg + IGMP_CHECKSUM_OFFSET) = 0;
-
- checksum = in_cksum(igmp_msg, igmp_msg_len);
- if (checksum != recv_checksum) {
- zlog_warn("Recv IGMP report v3 from %s on %s: checksum mismatch: received=%x computed=%x",
- from_str, ifp->name, recv_checksum, checksum);
- return -1;
- }
-
- num_groups = ntohs(*(uint16_t *) (igmp_msg + IGMP_V3_REPORT_NUMGROUPS_OFFSET));
- if (num_groups < 1) {
- zlog_warn("Recv IGMP report v3 from %s on %s: missing group records",
- from_str, ifp->name);
- return -1;
- }
-
- if (PIM_DEBUG_IGMP_PACKETS) {
- zlog_debug("Recv IGMP report v3 from %s on %s: size=%d checksum=%x groups=%d",
- from_str, ifp->name, igmp_msg_len, checksum, num_groups);
- }
-
- group_record = (uint8_t *) igmp_msg + IGMP_V3_REPORT_GROUPPRECORD_OFFSET;
-
- /* Scan groups */
- for (i = 0; i < num_groups; ++i) {
- struct in_addr rec_group;
- uint8_t *sources;
- uint8_t *src;
- int rec_type;
- int rec_auxdatalen;
- int rec_num_sources;
- int j;
- struct prefix lncb;
- struct prefix g;
-
- if ((group_record + IGMP_V3_GROUP_RECORD_MIN_SIZE) > report_pastend) {
- zlog_warn("Recv IGMP report v3 from %s on %s: group record beyond report end",
- from_str, ifp->name);
- return -1;
- }
-
- rec_type = group_record[IGMP_V3_GROUP_RECORD_TYPE_OFFSET];
- rec_auxdatalen = group_record[IGMP_V3_GROUP_RECORD_AUXDATALEN_OFFSET];
- rec_num_sources = ntohs(* (uint16_t *) (group_record + IGMP_V3_GROUP_RECORD_NUMSOURCES_OFFSET));
-
- memcpy(&rec_group, group_record + IGMP_V3_GROUP_RECORD_GROUP_OFFSET, sizeof(struct in_addr));
-
- if (PIM_DEBUG_IGMP_PACKETS) {
- zlog_debug("Recv IGMP report v3 from %s on %s: record=%d type=%d auxdatalen=%d sources=%d group=%s",
- from_str, ifp->name, i, rec_type, rec_auxdatalen, rec_num_sources, inet_ntoa(rec_group));
- }
-
- /* Scan sources */
-
- sources = group_record + IGMP_V3_GROUP_RECORD_SOURCE_OFFSET;
-
- for (j = 0, src = sources; j < rec_num_sources; ++j, src += 4) {
-
- if ((src + 4) > report_pastend) {
- zlog_warn("Recv IGMP report v3 from %s on %s: group source beyond report end",
- from_str, ifp->name);
- return -1;
- }
-
- if (PIM_DEBUG_IGMP_PACKETS) {
- char src_str[200];
-
- if (!inet_ntop(AF_INET, src, src_str , sizeof(src_str)))
- sprintf(src_str, "<source?>");
-
- zlog_debug("Recv IGMP report v3 from %s on %s: record=%d group=%s source=%s",
- from_str, ifp->name, i, inet_ntoa(rec_group), src_str);
- }
- } /* for (sources) */
-
-
- lncb.family = AF_INET;
- lncb.u.prefix4.s_addr = 0x000000E0;
- lncb.prefixlen = 24;
-
- g.family = AF_INET;
- g.u.prefix4 = rec_group;
- g.prefixlen = 32;
- /*
- * If we receive a igmp report with the group in 224.0.0.0/24
- * then we should ignore it
- */
- if (prefix_match(&lncb, &g))
- local_ncb = 1;
-
- if (!local_ncb)
- switch (rec_type) {
- case IGMP_GRP_REC_TYPE_MODE_IS_INCLUDE:
- igmpv3_report_isin(igmp, from, rec_group, rec_num_sources, (struct in_addr *) sources);
- break;
- case IGMP_GRP_REC_TYPE_MODE_IS_EXCLUDE:
- igmpv3_report_isex(igmp, from, rec_group, rec_num_sources, (struct in_addr *) sources, 0);
- break;
- case IGMP_GRP_REC_TYPE_CHANGE_TO_INCLUDE_MODE:
- igmpv3_report_toin(igmp, from, rec_group, rec_num_sources, (struct in_addr *) sources);
- break;
- case IGMP_GRP_REC_TYPE_CHANGE_TO_EXCLUDE_MODE:
- igmpv3_report_toex(igmp, from, rec_group, rec_num_sources, (struct in_addr *) sources);
- break;
- case IGMP_GRP_REC_TYPE_ALLOW_NEW_SOURCES:
- igmpv3_report_allow(igmp, from, rec_group, rec_num_sources, (struct in_addr *) sources);
- break;
- case IGMP_GRP_REC_TYPE_BLOCK_OLD_SOURCES:
- igmpv3_report_block(igmp, from, rec_group, rec_num_sources, (struct in_addr *) sources);
- break;
- default:
- zlog_warn("Recv IGMP report v3 from %s on %s: unknown record type: type=%d",
- from_str, ifp->name, rec_type);
- }
-
- group_record += 8 + (rec_num_sources << 2) + (rec_auxdatalen << 2);
- local_ncb = 0;
-
- } /* for (group records) */
-
- return 0;
+ uint16_t recv_checksum;
+ uint16_t checksum;
+ int num_groups;
+ uint8_t *group_record;
+ uint8_t *report_pastend = (uint8_t *)igmp_msg + igmp_msg_len;
+ struct interface *ifp = igmp->interface;
+ int i;
+ int local_ncb = 0;
+
+ if (igmp_msg_len < IGMP_V3_MSG_MIN_SIZE) {
+ zlog_warn(
+ "Recv IGMP report v3 from %s on %s: size=%d shorter than minimum=%d",
+ from_str, ifp->name, igmp_msg_len,
+ IGMP_V3_MSG_MIN_SIZE);
+ return -1;
+ }
+
+ recv_checksum = *(uint16_t *)(igmp_msg + IGMP_CHECKSUM_OFFSET);
+
+ /* for computing checksum */
+ *(uint16_t *)(igmp_msg + IGMP_CHECKSUM_OFFSET) = 0;
+
+ checksum = in_cksum(igmp_msg, igmp_msg_len);
+ if (checksum != recv_checksum) {
+ zlog_warn(
+ "Recv IGMP report v3 from %s on %s: checksum mismatch: received=%x computed=%x",
+ from_str, ifp->name, recv_checksum, checksum);
+ return -1;
+ }
+
+ num_groups = ntohs(
+ *(uint16_t *)(igmp_msg + IGMP_V3_REPORT_NUMGROUPS_OFFSET));
+ if (num_groups < 1) {
+ zlog_warn(
+ "Recv IGMP report v3 from %s on %s: missing group records",
+ from_str, ifp->name);
+ return -1;
+ }
+
+ if (PIM_DEBUG_IGMP_PACKETS) {
+ zlog_debug(
+ "Recv IGMP report v3 from %s on %s: size=%d checksum=%x groups=%d",
+ from_str, ifp->name, igmp_msg_len, checksum,
+ num_groups);
+ }
+
+ group_record = (uint8_t *)igmp_msg + IGMP_V3_REPORT_GROUPPRECORD_OFFSET;
+
+ /* Scan groups */
+ for (i = 0; i < num_groups; ++i) {
+ struct in_addr rec_group;
+ uint8_t *sources;
+ uint8_t *src;
+ int rec_type;
+ int rec_auxdatalen;
+ int rec_num_sources;
+ int j;
+ struct prefix lncb;
+ struct prefix g;
+
+ if ((group_record + IGMP_V3_GROUP_RECORD_MIN_SIZE)
+ > report_pastend) {
+ zlog_warn(
+ "Recv IGMP report v3 from %s on %s: group record beyond report end",
+ from_str, ifp->name);
+ return -1;
+ }
+
+ rec_type = group_record[IGMP_V3_GROUP_RECORD_TYPE_OFFSET];
+ rec_auxdatalen =
+ group_record[IGMP_V3_GROUP_RECORD_AUXDATALEN_OFFSET];
+ rec_num_sources = ntohs(*(
+ uint16_t *)(group_record
+ + IGMP_V3_GROUP_RECORD_NUMSOURCES_OFFSET));
+
+ memcpy(&rec_group,
+ group_record + IGMP_V3_GROUP_RECORD_GROUP_OFFSET,
+ sizeof(struct in_addr));
+
+ if (PIM_DEBUG_IGMP_PACKETS) {
+ zlog_debug(
+ "Recv IGMP report v3 from %s on %s: record=%d type=%d auxdatalen=%d sources=%d group=%s",
+ from_str, ifp->name, i, rec_type,
+ rec_auxdatalen, rec_num_sources,
+ inet_ntoa(rec_group));
+ }
+
+ /* Scan sources */
+
+ sources = group_record + IGMP_V3_GROUP_RECORD_SOURCE_OFFSET;
+
+ for (j = 0, src = sources; j < rec_num_sources; ++j, src += 4) {
+
+ if ((src + 4) > report_pastend) {
+ zlog_warn(
+ "Recv IGMP report v3 from %s on %s: group source beyond report end",
+ from_str, ifp->name);
+ return -1;
+ }
+
+ if (PIM_DEBUG_IGMP_PACKETS) {
+ char src_str[200];
+
+ if (!inet_ntop(AF_INET, src, src_str,
+ sizeof(src_str)))
+ sprintf(src_str, "<source?>");
+
+ zlog_debug(
+ "Recv IGMP report v3 from %s on %s: record=%d group=%s source=%s",
+ from_str, ifp->name, i,
+ inet_ntoa(rec_group), src_str);
+ }
+ } /* for (sources) */
+
+
+ lncb.family = AF_INET;
+ lncb.u.prefix4.s_addr = 0x000000E0;
+ lncb.prefixlen = 24;
+
+ g.family = AF_INET;
+ g.u.prefix4 = rec_group;
+ g.prefixlen = 32;
+ /*
+ * If we receive a igmp report with the group in 224.0.0.0/24
+ * then we should ignore it
+ */
+ if (prefix_match(&lncb, &g))
+ local_ncb = 1;
+
+ if (!local_ncb)
+ switch (rec_type) {
+ case IGMP_GRP_REC_TYPE_MODE_IS_INCLUDE:
+ igmpv3_report_isin(igmp, from, rec_group,
+ rec_num_sources,
+ (struct in_addr *)sources);
+ break;
+ case IGMP_GRP_REC_TYPE_MODE_IS_EXCLUDE:
+ igmpv3_report_isex(
+ igmp, from, rec_group, rec_num_sources,
+ (struct in_addr *)sources, 0);
+ break;
+ case IGMP_GRP_REC_TYPE_CHANGE_TO_INCLUDE_MODE:
+ igmpv3_report_toin(igmp, from, rec_group,
+ rec_num_sources,
+ (struct in_addr *)sources);
+ break;
+ case IGMP_GRP_REC_TYPE_CHANGE_TO_EXCLUDE_MODE:
+ igmpv3_report_toex(igmp, from, rec_group,
+ rec_num_sources,
+ (struct in_addr *)sources);
+ break;
+ case IGMP_GRP_REC_TYPE_ALLOW_NEW_SOURCES:
+ igmpv3_report_allow(igmp, from, rec_group,
+ rec_num_sources,
+ (struct in_addr *)sources);
+ break;
+ case IGMP_GRP_REC_TYPE_BLOCK_OLD_SOURCES:
+ igmpv3_report_block(igmp, from, rec_group,
+ rec_num_sources,
+ (struct in_addr *)sources);
+ break;
+ default:
+ zlog_warn(
+ "Recv IGMP report v3 from %s on %s: unknown record type: type=%d",
+ from_str, ifp->name, rec_type);
+ }
+
+ group_record +=
+ 8 + (rec_num_sources << 2) + (rec_auxdatalen << 2);
+ local_ncb = 0;
+
+ } /* for (group records) */
+
+ return 0;
}