include $(TOPDIR)/rules.mk
PKG_NAME:=igmpproxy
-PKG_VERSION:=0.1
-PKG_RELEASE:=11
+PKG_VERSION:=0.2.1
+PKG_RELEASE:=1
PKG_SOURCE:=$(PKG_NAME)-$(PKG_VERSION).tar.gz
-PKG_SOURCE_URL:=@SF/igmpproxy
-PKG_HASH:=ee18ff3d8c3ae3a29dccb7e5eedf332337330020168bd95a11cece8d7d7ee6ae
+PKG_SOURCE_URL:=https://github.com/pali/igmpproxy/releases/download/${PKG_VERSION}/
+PKG_HASH:=d351e623037390f575c1203d9cbb7ba33a8bdef85a3c5e1d2901c5a2a38449a1
PKG_MAINTAINER:=Felix Fietkau <nbd@nbd.name>
include $(INCLUDE_DIR)/package.mk
+++ /dev/null
-From fed8c3db10bc9d3a1e799a774924c00522595d0c Mon Sep 17 00:00:00 2001
-From: Evgeny Yurchenko <evg.yurch@rogers.com>
-Date: Mon, 4 Jan 2010 05:13:59 +0500
-Subject: [PATCH] Send IGMP packets with IP Router Alert option [RFC 2113] included in IP header
-
----
- src/igmp.c | 17 ++++++++++++-----
- src/igmpproxy.h | 1 +
- 2 files changed, 13 insertions(+), 5 deletions(-)
-
-diff --git a/src/igmp.c b/src/igmp.c
-index a0cd27d..b547688 100644
---- a/src/igmp.c
-+++ b/src/igmp.c
-@@ -67,7 +67,7 @@ void initIgmp() {
- * - Checksum (let the kernel fill it in)
- */
- ip->ip_v = IPVERSION;
-- ip->ip_hl = sizeof(struct ip) >> 2;
-+ ip->ip_hl = (sizeof(struct ip) + 4) >> 2; /* +4 for Router Alert option */
- ip->ip_tos = 0xc0; /* Internet Control */
- ip->ip_ttl = MAXTTL; /* applies to unicasts only */
- ip->ip_p = IPPROTO_IGMP;
-@@ -213,7 +213,7 @@ void buildIgmp(uint32_t src, uint32_t dst, int type, int code, uint32_t group, i
- ip = (struct ip *)send_buf;
- ip->ip_src.s_addr = src;
- ip->ip_dst.s_addr = dst;
-- ip_set_len(ip, MIN_IP_HEADER_LEN + IGMP_MINLEN + datalen);
-+ ip_set_len(ip, IP_HEADER_RAOPT_LEN + IGMP_MINLEN + datalen);
-
- if (IN_MULTICAST(ntohl(dst))) {
- ip->ip_ttl = curttl;
-@@ -221,13 +221,20 @@ void buildIgmp(uint32_t src, uint32_t dst, int type, int code, uint32_t group, i
- ip->ip_ttl = MAXTTL;
- }
-
-- igmp = (struct igmp *)(send_buf + MIN_IP_HEADER_LEN);
-+ /* Add Router Alert option */
-+ ((u_char*)send_buf+MIN_IP_HEADER_LEN)[0] = IPOPT_RA;
-+ ((u_char*)send_buf+MIN_IP_HEADER_LEN)[1] = 0x04;
-+ ((u_char*)send_buf+MIN_IP_HEADER_LEN)[2] = 0x00;
-+ ((u_char*)send_buf+MIN_IP_HEADER_LEN)[3] = 0x00;
-+
-+ igmp = (struct igmp *)(send_buf + IP_HEADER_RAOPT_LEN);
- igmp->igmp_type = type;
- igmp->igmp_code = code;
- igmp->igmp_group.s_addr = group;
- igmp->igmp_cksum = 0;
- igmp->igmp_cksum = inetChksum((u_short *)igmp,
-- IGMP_MINLEN + datalen);
-+ IP_HEADER_RAOPT_LEN + datalen);
-+
- }
-
- /*
-@@ -257,7 +264,7 @@ void sendIgmp(uint32_t src, uint32_t dst, int type, int code, uint32_t group, in
- #endif
- sdst.sin_addr.s_addr = dst;
- if (sendto(MRouterFD, send_buf,
-- MIN_IP_HEADER_LEN + IGMP_MINLEN + datalen, 0,
-+ IP_HEADER_RAOPT_LEN + IGMP_MINLEN + datalen, 0,
- (struct sockaddr *)&sdst, sizeof(sdst)) < 0) {
- if (errno == ENETDOWN)
- my_log(LOG_ERR, errno, "Sender VIF was down.");
-diff --git a/src/igmpproxy.h b/src/igmpproxy.h
-index 0de7791..4df8a79 100644
---- a/src/igmpproxy.h
-+++ b/src/igmpproxy.h
-@@ -64,6 +64,7 @@
- #define MAX_IP_PACKET_LEN 576
- #define MIN_IP_HEADER_LEN 20
- #define MAX_IP_HEADER_LEN 60
-+#define IP_HEADER_RAOPT_LEN 24
-
- #define MAX_MC_VIFS 32 // !!! check this const in the specific includes
-
---
-1.7.2.5
-
+++ /dev/null
-From 85e240727305b156097ee7aa0f0c4473a136291f Mon Sep 17 00:00:00 2001
-From: Constantin Baranov <const@mimas.ru>
-Date: Tue, 23 Feb 2010 21:08:02 +0400
-Subject: [PATCH] Change default interface state to disabled (wrt #2945877)
-
----
- src/ifvc.c | 2 +-
- src/igmpproxy.c | 6 ++++--
- 2 files changed, 5 insertions(+), 3 deletions(-)
-
-diff --git a/src/ifvc.c b/src/ifvc.c
-index 545b3b4..9d7ee97 100644
---- a/src/ifvc.c
-+++ b/src/ifvc.c
-@@ -139,7 +139,7 @@ void buildIfVc() {
- IfDescEp->allowednets->subnet_addr = subnet;
-
- // Set the default params for the IF...
-- IfDescEp->state = IF_STATE_DOWNSTREAM;
-+ IfDescEp->state = IF_STATE_DISABLED;
- IfDescEp->robustness = DEFAULT_ROBUSTNESS;
- IfDescEp->threshold = DEFAULT_THRESHOLD; /* ttl limit */
- IfDescEp->ratelimit = DEFAULT_RATELIMIT;
-diff --git a/src/igmpproxy.c b/src/igmpproxy.c
-index 1ece15a..35000c7 100644
---- a/src/igmpproxy.c
-+++ b/src/igmpproxy.c
-@@ -186,8 +186,10 @@ int igmpProxyInit() {
- }
- }
-
-- addVIF( Dp );
-- vifcount++;
-+ if (Dp->state != IF_STATE_DISABLED) {
-+ addVIF( Dp );
-+ vifcount++;
-+ }
- }
- }
-
---
-1.7.2.5
-
+++ /dev/null
-From 65f777e7f66b55239d935c1cf81bb5abc0f6c89f Mon Sep 17 00:00:00 2001
-From: Grinch <grinch79@users.sourceforge.net>
-Date: Sun, 16 Aug 2009 19:58:26 +0500
-Subject: [PATCH] Restrict igmp reports for downstream interfaces (wrt #2833339)
-
-atm all igmp membership reports are forwarded to the upstream interface.
-Unfortunately some ISP Providers restrict some multicast groups (esp. those
-that are defined as local link groups and that are not supposed to be
-forwarded to the wan, i.e 224.0.0.0/24). Therefore there should be some
-kind of black oder whitelisting.
-As whitelisting can be accomplished quite easy I wrote a litte patch, which
-is attached to this request.
----
- doc/igmpproxy.conf.5.in | 19 +++++++++++++++++++
- src/config.c | 23 ++++++++++++++++++++++-
- src/igmpproxy.h | 1 +
- src/request.c | 20 ++++++++++++++++----
- 4 files changed, 58 insertions(+), 5 deletions(-)
-
-diff --git a/doc/igmpproxy.conf.5.in b/doc/igmpproxy.conf.5.in
-index a4ea7d0..56efa22 100644
---- a/doc/igmpproxy.conf.5.in
-+++ b/doc/igmpproxy.conf.5.in
-@@ -116,6 +116,25 @@ This is especially useful for the upstream interface, since the source for multi
- traffic is often from a remote location. Any number of altnet parameters can be specified.
- .RE
-
-+.B whitelist
-+.I networkaddr
-+.RS
-+Defines a whitelist for multicast groups. The network address must be in the following
-+format 'a.b.c.d/n'. If you want to allow one single group use a network mask of /32,
-+i.e. 'a.b.c.d/32'.
-+
-+By default all multicast groups are allowed on any downstream interface. If at least one
-+whitelist entry is defined, all igmp membership reports for not explicitly whitelisted
-+multicast groups will be ignored and therefore not be served by igmpproxy. This is especially
-+useful, if your provider does only allow a predefined set of multicast groups. These whitelists
-+are only obeyed by igmpproxy itself, they won't prevent any other igmp client running on the
-+same machine as igmpproxy from requesting 'unallowed' multicast groups.
-+
-+You may specify as many whitelist entries as needed. Although you should keep it as simple as
-+possible, as this list is parsed for every membership report and therefore this increases igmp
-+response times. Often used or large groups should be defined first, as parsing ends as soon as
-+a group matches an entry.
-+.RE
-
- .SH EXAMPLE
- ## Enable quickleave
-diff --git a/src/config.c b/src/config.c
-index 5a96ce0..d72619f 100644
---- a/src/config.c
-+++ b/src/config.c
-@@ -46,6 +46,9 @@ struct vifconfig {
-
- // Keep allowed nets for VIF.
- struct SubnetList* allowednets;
-+
-+ // Allowed Groups
-+ struct SubnetList* allowedgroups;
-
- // Next config in list...
- struct vifconfig* next;
-@@ -202,6 +205,8 @@ void configureVifs() {
- // Insert the configured nets...
- vifLast->next = confPtr->allowednets;
-
-+ Dp->allowedgroups = confPtr->allowedgroups;
-+
- break;
- }
- }
-@@ -215,7 +220,7 @@ void configureVifs() {
- */
- struct vifconfig *parsePhyintToken() {
- struct vifconfig *tmpPtr;
-- struct SubnetList **anetPtr;
-+ struct SubnetList **anetPtr, **agrpPtr;
- char *token;
- short parseError = 0;
-
-@@ -239,6 +244,7 @@ struct vifconfig *parsePhyintToken() {
- tmpPtr->threshold = 1;
- tmpPtr->state = IF_STATE_DOWNSTREAM;
- tmpPtr->allowednets = NULL;
-+ tmpPtr->allowedgroups = NULL;
-
- // Make a copy of the token to store the IF name
- tmpPtr->name = strdup( token );
-@@ -248,6 +254,7 @@ struct vifconfig *parsePhyintToken() {
-
- // Set the altnet pointer to the allowednets pointer.
- anetPtr = &tmpPtr->allowednets;
-+ agrpPtr = &tmpPtr->allowedgroups;
-
- // Parse the rest of the config..
- token = nextConfigToken();
-@@ -266,6 +273,20 @@ struct vifconfig *parsePhyintToken() {
- anetPtr = &(*anetPtr)->next;
- }
- }
-+ else if(strcmp("whitelist", token)==0) {
-+ // Whitelist
-+ token = nextConfigToken();
-+ my_log(LOG_DEBUG, 0, "Config: IF: Got whitelist token %s.", token);
-+
-+ *agrpPtr = parseSubnetAddress(token);
-+ if(*agrpPtr == NULL) {
-+ parseError = 1;
-+ my_log(LOG_WARNING, 0, "Unable to parse subnet address.");
-+ break;
-+ } else {
-+ agrpPtr = &(*agrpPtr)->next;
-+ }
-+ }
- else if(strcmp("upstream", token)==0) {
- // Upstream
- my_log(LOG_DEBUG, 0, "Config: IF: Got upstream token.");
-diff --git a/src/igmpproxy.h b/src/igmpproxy.h
-index 4dabd1c..0de7791 100644
---- a/src/igmpproxy.h
-+++ b/src/igmpproxy.h
-@@ -145,6 +145,7 @@ struct IfDesc {
- short Flags;
- short state;
- struct SubnetList* allowednets;
-+ struct SubnetList* allowedgroups;
- unsigned int robustness;
- unsigned char threshold; /* ttl limit */
- unsigned int ratelimit;
-diff --git a/src/request.c b/src/request.c
-index e3589f6..89b91de 100644
---- a/src/request.c
-+++ b/src/request.c
-@@ -82,10 +82,22 @@ void acceptGroupReport(uint32_t src, uint32_t group, uint8_t type) {
- my_log(LOG_DEBUG, 0, "Should insert group %s (from: %s) to route table. Vif Ix : %d",
- inetFmt(group,s1), inetFmt(src,s2), sourceVif->index);
-
-- // The membership report was OK... Insert it into the route table..
-- insertRoute(group, sourceVif->index);
--
--
-+ // If we don't have a whitelist we insertRoute and done
-+ if(sourceVif->allowedgroups == NULL)
-+ {
-+ insertRoute(group, sourceVif->index);
-+ return;
-+ }
-+ // Check if this Request is legit on this interface
-+ struct SubnetList *sn;
-+ for(sn = sourceVif->allowedgroups; sn != NULL; sn = sn->next)
-+ if((group & sn->subnet_mask) == sn->subnet_addr)
-+ {
-+ // The membership report was OK... Insert it into the route table..
-+ insertRoute(group, sourceVif->index);
-+ return;
-+ }
-+ my_log(LOG_INFO, 0, "The group address %s may not be requested from this interface. Ignoring.", inetFmt(group, s1));
- } else {
- // Log the state of the interface the report was recieved on.
- my_log(LOG_INFO, 0, "Mebership report was recieved on %s. Ignoring.",
---
-1.7.2.5
-
+++ /dev/null
-From bcd7c648e86d97263c931de53a008c9629e7797e Mon Sep 17 00:00:00 2001
-From: Stefan Becker <stefan.becker@nokia.com>
-Date: Fri, 11 Dec 2009 21:08:57 +0200
-Subject: [PATCH] Restrict igmp reports forwarding to upstream interface
-
-Utilize the new "whitelist" keyword also on the upstream interface definition.
-If specified then only whitelisted multicast groups will be forwarded upstream.
-
-This can be used to avoid publishing private multicast groups to the world,
-e.g. SSDP from a UPnP server on the internal network.
----
- doc/igmpproxy.conf.5.in | 5 +++++
- src/rttable.c | 17 +++++++++++++++++
- 2 files changed, 22 insertions(+), 0 deletions(-)
-
-diff --git a/doc/igmpproxy.conf.5.in b/doc/igmpproxy.conf.5.in
-index 56efa22..d916f05 100644
---- a/doc/igmpproxy.conf.5.in
-+++ b/doc/igmpproxy.conf.5.in
-@@ -134,6 +134,11 @@ You may specify as many whitelist entries as needed. Although you should keep it
- possible, as this list is parsed for every membership report and therefore this increases igmp
- response times. Often used or large groups should be defined first, as parsing ends as soon as
- a group matches an entry.
-+
-+You may also specify whitelist entries for the upstream interface. Only igmp membership reports
-+for explicitely whitelisted multicast groups will be sent out on the upstream interface. This
-+is useful if you want to use multicast groups only between your downstream interfaces, like SSDP
-+from a UPnP server.
- .RE
-
- .SH EXAMPLE
-diff --git a/src/rttable.c b/src/rttable.c
-index f0701a8..77dd791 100644
---- a/src/rttable.c
-+++ b/src/rttable.c
-@@ -117,6 +117,23 @@ void sendJoinLeaveUpstream(struct RouteTable* route, int join) {
- my_log(LOG_ERR, 0 ,"FATAL: Unable to get Upstream IF.");
- }
-
-+ // Check if there is a white list for the upstram VIF
-+ if (upstrIf->allowedgroups != NULL) {
-+ uint32_t group = route->group;
-+ struct SubnetList* sn;
-+
-+ // Check if this Request is legit to be forwarded to upstream
-+ for(sn = upstrIf->allowedgroups; sn != NULL; sn = sn->next)
-+ if((group & sn->subnet_mask) == sn->subnet_addr)
-+ // Forward is OK...
-+ break;
-+
-+ if (sn == NULL) {
-+ my_log(LOG_INFO, 0, "The group address %s may not be forwarded upstream. Ignoring.", inetFmt(group, s1));
-+ return;
-+ }
-+ }
-+
- // Send join or leave request...
- if(join) {
-
---
-1.7.2.5
-
+++ /dev/null
---- a/src/os-linux.h
-+++ b/src/os-linux.h
-@@ -3,6 +3,7 @@
- #include <linux/mroute.h>
- #include <netinet/ip.h>
- #include <netinet/igmp.h>
-+#include <sys/types.h>
-
- static inline u_short ip_data_len(const struct ip *ip)
- {
+++ /dev/null
---- a/src/igmp.c
-+++ b/src/igmp.c
-@@ -139,8 +139,14 @@
- return;
- }
- else if(!isAdressValidForIf(checkVIF, src)) {
-- my_log(LOG_WARNING, 0, "The source address %s for group %s, is not in any valid net for upstream VIF.",
-- inetFmt(src, s1), inetFmt(dst, s2));
-+ struct IfDesc *downVIF = getIfByAddress(src);
-+ if (downVIF && downVIF->state & IF_STATE_DOWNSTREAM) {
-+ my_log(LOG_NOTICE, 0, "The source address %s for group %s is from downstream VIF. Ignoring.",
-+ inetFmt(src, s1), inetFmt(dst, s2));
-+ } else {
-+ my_log(LOG_WARNING, 0, "The source address %s for group %s, is not in any valid net for upstream VIF.",
-+ inetFmt(src, s1), inetFmt(dst, s2));
-+ }
- return;
- }
-
+++ /dev/null
-From d0e66e0719ae8eb549f7cc220fdc66575d3db332 Mon Sep 17 00:00:00 2001
-From: Jonas Gorski <jonas.gorski@gmail.com>
-Date: Thu, 29 Mar 2012 17:01:11 +0200
-Subject: [PATCH 4/4] use monotic clock instead of time of day
-
-The time of day might chance e.g. by daylight savings time during the
-runtime, which causes timers to fire repeatedly for a long time.
-
-Contributed by T-Labs, Deutsche Telekom Innovation Laboratories
-
-Signed-off-by: Jonas Gorski <jonas.gorski@gmail.com>
----
- configure.ac | 2 ++
- src/igmpproxy.c | 26 +++++++++++++-------------
- src/igmpproxy.h | 3 ++-
- 3 files changed, 17 insertions(+), 14 deletions(-)
-
-diff --git a/configure.ac b/configure.ac
-index 85beb08..bd84eba 100644
---- a/configure.ac
-+++ b/configure.ac
-@@ -25,6 +25,8 @@ AC_CHECK_MEMBERS([struct sockaddr_in.sin_len], [], [], [[
- #include <netinet/in.h>
- ]])
-
-+AC_SEARCH_LIBS([clock_gettime],[rt])
-+
- AC_CONFIG_FILES([
- Makefile
- doc/Makefile
-diff --git a/src/igmpproxy.c b/src/igmpproxy.c
-index 35000c7..3a9ccad 100644
---- a/src/igmpproxy.c
-+++ b/src/igmpproxy.c
-@@ -234,13 +234,13 @@ void igmpProxyRun() {
- int MaxFD, Rt, secs;
- fd_set ReadFDS;
- socklen_t dummy = 0;
-- struct timeval curtime, lasttime, difftime, tv;
-+ struct timespec curtime, lasttime, difftime, tv;
- // The timeout is a pointer in order to set it to NULL if nessecary.
-- struct timeval *timeout = &tv;
-+ struct timespec *timeout = &tv;
-
- // Initialize timer vars
-- difftime.tv_usec = 0;
-- gettimeofday(&curtime, NULL);
-+ difftime.tv_nsec = 0;
-+ clock_gettime(CLOCK_MONOTONIC, &curtime);
- lasttime = curtime;
-
- // First thing we send a membership query in downstream VIF's...
-@@ -263,7 +263,7 @@ void igmpProxyRun() {
- if(secs == -1) {
- timeout = NULL;
- } else {
-- timeout->tv_usec = 0;
-+ timeout->tv_nsec = 0;
- timeout->tv_sec = secs;
- }
-
-@@ -274,7 +274,7 @@ void igmpProxyRun() {
- FD_SET( MRouterFD, &ReadFDS );
-
- // wait for input
-- Rt = select( MaxFD +1, &ReadFDS, NULL, NULL, timeout );
-+ Rt = pselect( MaxFD +1, &ReadFDS, NULL, NULL, timeout, NULL );
-
- // log and ignore failures
- if( Rt < 0 ) {
-@@ -307,20 +307,20 @@ void igmpProxyRun() {
- */
- if (Rt == 0) {
- curtime.tv_sec = lasttime.tv_sec + secs;
-- curtime.tv_usec = lasttime.tv_usec;
-+ curtime.tv_nsec = lasttime.tv_nsec;
- Rt = -1; /* don't do this next time through the loop */
- } else {
-- gettimeofday(&curtime, NULL);
-+ clock_gettime(CLOCK_MONOTONIC, &curtime);
- }
- difftime.tv_sec = curtime.tv_sec - lasttime.tv_sec;
-- difftime.tv_usec += curtime.tv_usec - lasttime.tv_usec;
-- while (difftime.tv_usec > 1000000) {
-+ difftime.tv_nsec += curtime.tv_nsec - lasttime.tv_nsec;
-+ while (difftime.tv_nsec > 1000000000) {
- difftime.tv_sec++;
-- difftime.tv_usec -= 1000000;
-+ difftime.tv_nsec -= 1000000000;
- }
-- if (difftime.tv_usec < 0) {
-+ if (difftime.tv_nsec < 0) {
- difftime.tv_sec--;
-- difftime.tv_usec += 1000000;
-+ difftime.tv_nsec += 1000000000;
- }
- lasttime = curtime;
- if (secs == 0 || difftime.tv_sec > 0)
-diff --git a/src/igmpproxy.h b/src/igmpproxy.h
-index 4df8a79..36a4f04 100644
---- a/src/igmpproxy.h
-+++ b/src/igmpproxy.h
-@@ -44,12 +44,13 @@
- #include <string.h>
- #include <fcntl.h>
- #include <stdbool.h>
-+#include <time.h>
-
- #include <sys/socket.h>
- #include <sys/un.h>
--#include <sys/time.h>
- #include <sys/ioctl.h>
- #include <sys/param.h>
-+#include <sys/select.h>
-
- #include <net/if.h>
- #include <netinet/in.h>
---
-1.7.2.5
-
+++ /dev/null
---- a/src/config.c
-+++ b/src/config.c
-@@ -357,15 +357,18 @@ struct SubnetList *parseSubnetAddress(ch
- tmpStr = strtok(NULL, "/");
- if(tmpStr != NULL) {
- int bitcnt = atoi(tmpStr);
-- if(bitcnt <= 0 || bitcnt > 32) {
-+ if(bitcnt < 0 || bitcnt > 32) {
- my_log(LOG_WARNING, 0, "The bits part of the address is invalid : %d.",tmpStr);
- return NULL;
- }
-
-- mask <<= (32 - bitcnt);
-+ if (bitcnt == 0)
-+ mask = 0;
-+ else
-+ mask <<= (32 - bitcnt);
- }
-
-- if(addr == -1 || addr == 0) {
-+ if(addr == -1) {
- my_log(LOG_WARNING, 0, "Unable to parse address token '%s'.", addrstr);
- return NULL;
- }
+++ /dev/null
---- a/src/igmpproxy.h
-+++ b/src/igmpproxy.h
-@@ -251,6 +251,7 @@ int activateRoute(uint32_t group, uint32
- void ageActiveRoutes();
- void setRouteLastMemberMode(uint32_t group);
- int lastMemberGroupAge(uint32_t group);
-+int interfaceInRoute(int32_t group, int Ix);
-
- /* request.c
- */
---- a/src/request.c
-+++ b/src/request.c
-@@ -41,10 +41,10 @@
-
- // Prototypes...
- void sendGroupSpecificMemberQuery(void *argument);
--
-+
- typedef struct {
- uint32_t group;
-- uint32_t vifAddr;
-+ // uint32_t vifAddr;
- short started;
- } GroupVifDesc;
-
-@@ -142,7 +142,7 @@ void acceptLeaveMessage(uint32_t src, ui
-
- // Call the group spesific membership querier...
- gvDesc->group = group;
-- gvDesc->vifAddr = sourceVif->InAdr.s_addr;
-+ // gvDesc->vifAddr = sourceVif->InAdr.s_addr;
- gvDesc->started = 0;
-
- sendGroupSpecificMemberQuery(gvDesc);
-@@ -159,6 +159,9 @@ void acceptLeaveMessage(uint32_t src, ui
- */
- void sendGroupSpecificMemberQuery(void *argument) {
- struct Config *conf = getCommonConfig();
-+ struct IfDesc *Dp;
-+ struct RouteTable *croute;
-+ int Ix;
-
- // Cast argument to correct type...
- GroupVifDesc *gvDesc = (GroupVifDesc*) argument;
-@@ -166,22 +169,38 @@ void sendGroupSpecificMemberQuery(void *
- if(gvDesc->started) {
- // If aging returns false, we don't do any further action...
- if(!lastMemberGroupAge(gvDesc->group)) {
-+ // FIXME: Should we free gvDesc here?
- return;
- }
- } else {
- gvDesc->started = 1;
- }
-
-- // Send a group specific membership query...
-- sendIgmp(gvDesc->vifAddr, gvDesc->group,
-- IGMP_MEMBERSHIP_QUERY,
-- conf->lastMemberQueryInterval * IGMP_TIMER_SCALE,
-- gvDesc->group, 0);
--
-- my_log(LOG_DEBUG, 0, "Sent membership query from %s to %s. Delay: %d",
-- inetFmt(gvDesc->vifAddr,s1), inetFmt(gvDesc->group,s2),
-- conf->lastMemberQueryInterval);
--
-+ /**
-+ * FIXME: This loops through all interfaces the group is active on an sends queries.
-+ * It might be better to send only a query on the interface the leave was accepted on and remove only that interface from the route.
-+ */
-+
-+ // Loop through all downstream interfaces
-+ for ( Ix = 0; (Dp = getIfByIx(Ix)); Ix++ ) {
-+ if ( Dp->InAdr.s_addr && ! (Dp->Flags & IFF_LOOPBACK) ) {
-+ if(Dp->state == IF_STATE_DOWNSTREAM) {
-+ // Is that interface used in the group?
-+ if (interfaceInRoute(gvDesc->group ,Dp->index)) {
-+
-+ // Send a group specific membership query...
-+ sendIgmp(Dp->InAdr.s_addr, gvDesc->group,
-+ IGMP_MEMBERSHIP_QUERY,
-+ conf->lastMemberQueryInterval * IGMP_TIMER_SCALE,
-+ gvDesc->group, 0);
-+
-+ my_log(LOG_DEBUG, 0, "Sent membership query from %s to %s. Delay: %d",
-+ inetFmt(Dp->InAdr.s_addr,s1), inetFmt(gvDesc->group,s2),
-+ conf->lastMemberQueryInterval);
-+ }
-+ }
-+ }
-+ }
- // Set timeout for next round...
- timer_setTimer(conf->lastMemberQueryInterval, sendGroupSpecificMemberQuery, gvDesc);
-
---- a/src/rttable.c
-+++ b/src/rttable.c
-@@ -428,6 +428,25 @@ void ageActiveRoutes() {
- }
-
- /**
-+* Counts the number of interfaces a given route is active on
-+*/
-+int numberOfInterfaces(struct RouteTable *croute) {
-+ int Ix;
-+ struct IfDesc *Dp;
-+ int result = 0;
-+ // Loop through all interfaces
-+ for ( Ix = 0; (Dp = getIfByIx(Ix)); Ix++ ) {
-+ // If the interface is used by the route, increase counter
-+ if(BIT_TST(croute->vifBits, Dp->index)) {
-+ result++;
-+ }
-+ }
-+ my_log(LOG_DEBUG, 0, "counted %d interfaces", result);
-+ return result;
-+}
-+
-+
-+/**
- * Should be called when a leave message is recieved, to
- * mark a route for the last member probe state.
- */
-@@ -439,8 +458,11 @@ void setRouteLastMemberMode(uint32_t gro
- if(croute!=NULL) {
- // Check for fast leave mode...
- if(croute->upstrState == ROUTESTATE_JOINED && conf->fastUpstreamLeave) {
-- // Send a leave message right away..
-- sendJoinLeaveUpstream(croute, 0);
-+ // Send a leave message right away only when the route has been active on only one interface
-+ if (numberOfInterfaces(croute) <= 1) {
-+ my_log(LOG_DEBUG, 0, "Leaving group %d now", group);
-+ sendJoinLeaveUpstream(croute, 0);
-+ }
- }
- // Set the routingstate to Last member check...
- croute->upstrState = ROUTESTATE_CHECK_LAST_MEMBER;
-@@ -677,3 +699,18 @@ void logRouteTable(char *header) {
-
- my_log(LOG_DEBUG, 0, "-----------------------------------------------------");
- }
-+
-+/**
-+* Returns true when the given group belongs to the given interface
-+*/
-+int interfaceInRoute(int32_t group, int Ix) {
-+ struct RouteTable* croute;
-+ croute = findRoute(group);
-+ if (croute != NULL) {
-+ my_log(LOG_DEBUG, 0, "Interface id %d is in group $d", Ix, group);
-+ return BIT_TST(croute->vifBits, Ix);
-+ } else {
-+ return 0;
-+ }
-+}
-+