aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid L Stevens <dlstevens@us.ibm.com>2005-07-08 20:39:23 -0400
committerDavid S. Miller <davem@davemloft.net>2005-07-08 20:39:23 -0400
commit8cdaaa15da58806ac3c75d96c40aef9e31445a25 (patch)
treebdeee63b026525963143d3ffe07d93110c25297c
parentca9b907d140a5f249250d19f956129dbbbf84f73 (diff)
[IPV4]: multicast API "join" issues
1) Changes IP_ADD_SOURCE_MEMBERSHIP and MCAST_JOIN_SOURCE_GROUP to ignore EADDRINUSE errors on a "courtesy join" -- prior membership or not is ok for these. 2) Adds "leave group" equivalence of (INCLUDE, empty) filters in the delta-based API. Without this, mixing delta-based API calls that end in an (INCLUDE, empty) filter would not allow a subsequent regular IP_ADD_MEMBERSHIP. It also frees socket buffer memory that isn't needed for both the multicast group record and source filter. Signed-off-by: David L Stevens <dlstevens@us.ibm.com> Signed-off-by: David S. Miller <davem@davemloft.net>
-rw-r--r--net/ipv4/igmp.c9
-rw-r--r--net/ipv4/ip_sockglue.c6
2 files changed, 12 insertions, 3 deletions
diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c
index 111eb678cbac..e21ebe759907 100644
--- a/net/ipv4/igmp.c
+++ b/net/ipv4/igmp.c
@@ -1724,6 +1724,7 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct
1724 struct in_device *in_dev = NULL; 1724 struct in_device *in_dev = NULL;
1725 struct inet_sock *inet = inet_sk(sk); 1725 struct inet_sock *inet = inet_sk(sk);
1726 struct ip_sf_socklist *psl; 1726 struct ip_sf_socklist *psl;
1727 int leavegroup = 0;
1727 int i, j, rv; 1728 int i, j, rv;
1728 1729
1729 if (!MULTICAST(addr)) 1730 if (!MULTICAST(addr))
@@ -1775,6 +1776,12 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct
1775 if (rv) /* source not found */ 1776 if (rv) /* source not found */
1776 goto done; 1777 goto done;
1777 1778
1779 /* special case - (INCLUDE, empty) == LEAVE_GROUP */
1780 if (psl->sl_count == 1 && omode == MCAST_INCLUDE) {
1781 leavegroup = 1;
1782 goto done;
1783 }
1784
1778 /* update the interface filter */ 1785 /* update the interface filter */
1779 ip_mc_del_src(in_dev, &mreqs->imr_multiaddr, omode, 1, 1786 ip_mc_del_src(in_dev, &mreqs->imr_multiaddr, omode, 1,
1780 &mreqs->imr_sourceaddr, 1); 1787 &mreqs->imr_sourceaddr, 1);
@@ -1831,6 +1838,8 @@ int ip_mc_source(int add, int omode, struct sock *sk, struct
1831 &mreqs->imr_sourceaddr, 1); 1838 &mreqs->imr_sourceaddr, 1);
1832done: 1839done:
1833 rtnl_shunlock(); 1840 rtnl_shunlock();
1841 if (leavegroup)
1842 return ip_mc_leave_group(sk, &imr);
1834 return err; 1843 return err;
1835} 1844}
1836 1845
diff --git a/net/ipv4/ip_sockglue.c b/net/ipv4/ip_sockglue.c
index f8b172f89811..fc7c481d0d79 100644
--- a/net/ipv4/ip_sockglue.c
+++ b/net/ipv4/ip_sockglue.c
@@ -677,11 +677,11 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
677 mreq.imr_address.s_addr = mreqs.imr_interface; 677 mreq.imr_address.s_addr = mreqs.imr_interface;
678 mreq.imr_ifindex = 0; 678 mreq.imr_ifindex = 0;
679 err = ip_mc_join_group(sk, &mreq); 679 err = ip_mc_join_group(sk, &mreq);
680 if (err) 680 if (err && err != -EADDRINUSE)
681 break; 681 break;
682 omode = MCAST_INCLUDE; 682 omode = MCAST_INCLUDE;
683 add = 1; 683 add = 1;
684 } else /*IP_DROP_SOURCE_MEMBERSHIP */ { 684 } else /* IP_DROP_SOURCE_MEMBERSHIP */ {
685 omode = MCAST_INCLUDE; 685 omode = MCAST_INCLUDE;
686 add = 0; 686 add = 0;
687 } 687 }
@@ -754,7 +754,7 @@ int ip_setsockopt(struct sock *sk, int level, int optname, char __user *optval,
754 mreq.imr_address.s_addr = 0; 754 mreq.imr_address.s_addr = 0;
755 mreq.imr_ifindex = greqs.gsr_interface; 755 mreq.imr_ifindex = greqs.gsr_interface;
756 err = ip_mc_join_group(sk, &mreq); 756 err = ip_mc_join_group(sk, &mreq);
757 if (err) 757 if (err && err != -EADDRINUSE)
758 break; 758 break;
759 greqs.gsr_interface = mreq.imr_ifindex; 759 greqs.gsr_interface = mreq.imr_ifindex;
760 omode = MCAST_INCLUDE; 760 omode = MCAST_INCLUDE;