Commit 8e05fd83 authored by David S. Miller's avatar David S. Miller

Merge branch 'multicast-init-as-INCLUDE-when-join-SSM-INCLUDE-group'

Hangbin Liu says:

====================
multicast: init as INCLUDE when join SSM INCLUDE group

Based on RFC3376 5.1 and RFC3810 6.1, we should init as INCLUDE when join SSM
INCLUDE group. In my first version I only clear the group change record. But
this is not enough as when a new group join, it will init as EXCLUDE and
trigger an filter mode change in ip/ip6_mc_add_src(), which will clear all
source addresses' sf_crcount. This will prevent early joined address sending
state change records if multi source addresses joined at the same time.

In this v2 patchset, I fixed it by directly initializing the mode to INCLUDE
for SSM JOIN_SOURCE_GROUP. I also split the original patch into two separated
patches for IPv4 and IPv6.

Test: test by myself and customer.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 6bed5e26 c7ea20c9
...@@ -109,6 +109,8 @@ struct ip_mc_list { ...@@ -109,6 +109,8 @@ struct ip_mc_list {
extern int ip_check_mc_rcu(struct in_device *dev, __be32 mc_addr, __be32 src_addr, u8 proto); extern int ip_check_mc_rcu(struct in_device *dev, __be32 mc_addr, __be32 src_addr, u8 proto);
extern int igmp_rcv(struct sk_buff *); extern int igmp_rcv(struct sk_buff *);
extern int ip_mc_join_group(struct sock *sk, struct ip_mreqn *imr); extern int ip_mc_join_group(struct sock *sk, struct ip_mreqn *imr);
extern int ip_mc_join_group_ssm(struct sock *sk, struct ip_mreqn *imr,
unsigned int mode);
extern int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr); extern int ip_mc_leave_group(struct sock *sk, struct ip_mreqn *imr);
extern void ip_mc_drop_socket(struct sock *sk); extern void ip_mc_drop_socket(struct sock *sk);
extern int ip_mc_source(int add, int omode, struct sock *sk, extern int ip_mc_source(int add, int omode, struct sock *sk,
......
...@@ -1100,6 +1100,8 @@ void ipv6_sysctl_unregister(void); ...@@ -1100,6 +1100,8 @@ void ipv6_sysctl_unregister(void);
int ipv6_sock_mc_join(struct sock *sk, int ifindex, int ipv6_sock_mc_join(struct sock *sk, int ifindex,
const struct in6_addr *addr); const struct in6_addr *addr);
int ipv6_sock_mc_join_ssm(struct sock *sk, int ifindex,
const struct in6_addr *addr, unsigned int mode);
int ipv6_sock_mc_drop(struct sock *sk, int ifindex, int ipv6_sock_mc_drop(struct sock *sk, int ifindex,
const struct in6_addr *addr); const struct in6_addr *addr);
#endif /* _NET_IPV6_H */ #endif /* _NET_IPV6_H */
...@@ -1200,13 +1200,14 @@ static void igmpv3_del_delrec(struct in_device *in_dev, struct ip_mc_list *im) ...@@ -1200,13 +1200,14 @@ static void igmpv3_del_delrec(struct in_device *in_dev, struct ip_mc_list *im)
spin_lock_bh(&im->lock); spin_lock_bh(&im->lock);
if (pmc) { if (pmc) {
im->interface = pmc->interface; im->interface = pmc->interface;
im->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
im->sfmode = pmc->sfmode; im->sfmode = pmc->sfmode;
if (pmc->sfmode == MCAST_INCLUDE) { if (pmc->sfmode == MCAST_INCLUDE) {
im->tomb = pmc->tomb; im->tomb = pmc->tomb;
im->sources = pmc->sources; im->sources = pmc->sources;
for (psf = im->sources; psf; psf = psf->sf_next) for (psf = im->sources; psf; psf = psf->sf_next)
psf->sf_crcount = im->crcount; psf->sf_crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
} else {
im->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
} }
in_dev_put(pmc->interface); in_dev_put(pmc->interface);
kfree(pmc); kfree(pmc);
...@@ -1288,7 +1289,7 @@ static void igmp_group_dropped(struct ip_mc_list *im) ...@@ -1288,7 +1289,7 @@ static void igmp_group_dropped(struct ip_mc_list *im)
#endif #endif
} }
static void igmp_group_added(struct ip_mc_list *im) static void igmp_group_added(struct ip_mc_list *im, unsigned int mode)
{ {
struct in_device *in_dev = im->interface; struct in_device *in_dev = im->interface;
#ifdef CONFIG_IP_MULTICAST #ifdef CONFIG_IP_MULTICAST
...@@ -1316,7 +1317,13 @@ static void igmp_group_added(struct ip_mc_list *im) ...@@ -1316,7 +1317,13 @@ static void igmp_group_added(struct ip_mc_list *im)
} }
/* else, v3 */ /* else, v3 */
im->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv; /* Based on RFC3376 5.1, for newly added INCLUDE SSM, we should
* not send filter-mode change record as the mode should be from
* IN() to IN(A).
*/
if (mode == MCAST_EXCLUDE)
im->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
igmp_ifc_event(in_dev); igmp_ifc_event(in_dev);
#endif #endif
} }
...@@ -1381,8 +1388,7 @@ static void ip_mc_hash_remove(struct in_device *in_dev, ...@@ -1381,8 +1388,7 @@ static void ip_mc_hash_remove(struct in_device *in_dev,
/* /*
* A socket has joined a multicast group on device dev. * A socket has joined a multicast group on device dev.
*/ */
void __ip_mc_inc_group(struct in_device *in_dev, __be32 addr, unsigned int mode)
void ip_mc_inc_group(struct in_device *in_dev, __be32 addr)
{ {
struct ip_mc_list *im; struct ip_mc_list *im;
#ifdef CONFIG_IP_MULTICAST #ifdef CONFIG_IP_MULTICAST
...@@ -1394,7 +1400,7 @@ void ip_mc_inc_group(struct in_device *in_dev, __be32 addr) ...@@ -1394,7 +1400,7 @@ void ip_mc_inc_group(struct in_device *in_dev, __be32 addr)
for_each_pmc_rtnl(in_dev, im) { for_each_pmc_rtnl(in_dev, im) {
if (im->multiaddr == addr) { if (im->multiaddr == addr) {
im->users++; im->users++;
ip_mc_add_src(in_dev, &addr, MCAST_EXCLUDE, 0, NULL, 0); ip_mc_add_src(in_dev, &addr, mode, 0, NULL, 0);
goto out; goto out;
} }
} }
...@@ -1408,8 +1414,8 @@ void ip_mc_inc_group(struct in_device *in_dev, __be32 addr) ...@@ -1408,8 +1414,8 @@ void ip_mc_inc_group(struct in_device *in_dev, __be32 addr)
in_dev_hold(in_dev); in_dev_hold(in_dev);
im->multiaddr = addr; im->multiaddr = addr;
/* initial mode is (EX, empty) */ /* initial mode is (EX, empty) */
im->sfmode = MCAST_EXCLUDE; im->sfmode = mode;
im->sfcount[MCAST_EXCLUDE] = 1; im->sfcount[mode] = 1;
refcount_set(&im->refcnt, 1); refcount_set(&im->refcnt, 1);
spin_lock_init(&im->lock); spin_lock_init(&im->lock);
#ifdef CONFIG_IP_MULTICAST #ifdef CONFIG_IP_MULTICAST
...@@ -1426,12 +1432,17 @@ void ip_mc_inc_group(struct in_device *in_dev, __be32 addr) ...@@ -1426,12 +1432,17 @@ void ip_mc_inc_group(struct in_device *in_dev, __be32 addr)
#ifdef CONFIG_IP_MULTICAST #ifdef CONFIG_IP_MULTICAST
igmpv3_del_delrec(in_dev, im); igmpv3_del_delrec(in_dev, im);
#endif #endif
igmp_group_added(im); igmp_group_added(im, mode);
if (!in_dev->dead) if (!in_dev->dead)
ip_rt_multicast_event(in_dev); ip_rt_multicast_event(in_dev);
out: out:
return; return;
} }
void ip_mc_inc_group(struct in_device *in_dev, __be32 addr)
{
__ip_mc_inc_group(in_dev, addr, MCAST_EXCLUDE);
}
EXPORT_SYMBOL(ip_mc_inc_group); EXPORT_SYMBOL(ip_mc_inc_group);
static int ip_mc_check_iphdr(struct sk_buff *skb) static int ip_mc_check_iphdr(struct sk_buff *skb)
...@@ -1688,7 +1699,7 @@ void ip_mc_remap(struct in_device *in_dev) ...@@ -1688,7 +1699,7 @@ void ip_mc_remap(struct in_device *in_dev)
#ifdef CONFIG_IP_MULTICAST #ifdef CONFIG_IP_MULTICAST
igmpv3_del_delrec(in_dev, pmc); igmpv3_del_delrec(in_dev, pmc);
#endif #endif
igmp_group_added(pmc); igmp_group_added(pmc, pmc->sfmode);
} }
} }
...@@ -1751,7 +1762,7 @@ void ip_mc_up(struct in_device *in_dev) ...@@ -1751,7 +1762,7 @@ void ip_mc_up(struct in_device *in_dev)
#ifdef CONFIG_IP_MULTICAST #ifdef CONFIG_IP_MULTICAST
igmpv3_del_delrec(in_dev, pmc); igmpv3_del_delrec(in_dev, pmc);
#endif #endif
igmp_group_added(pmc); igmp_group_added(pmc, pmc->sfmode);
} }
} }
...@@ -2130,8 +2141,8 @@ static void ip_mc_clear_src(struct ip_mc_list *pmc) ...@@ -2130,8 +2141,8 @@ static void ip_mc_clear_src(struct ip_mc_list *pmc)
/* Join a multicast group /* Join a multicast group
*/ */
static int __ip_mc_join_group(struct sock *sk, struct ip_mreqn *imr,
int ip_mc_join_group(struct sock *sk, struct ip_mreqn *imr) unsigned int mode)
{ {
__be32 addr = imr->imr_multiaddr.s_addr; __be32 addr = imr->imr_multiaddr.s_addr;
struct ip_mc_socklist *iml, *i; struct ip_mc_socklist *iml, *i;
...@@ -2172,15 +2183,30 @@ int ip_mc_join_group(struct sock *sk, struct ip_mreqn *imr) ...@@ -2172,15 +2183,30 @@ int ip_mc_join_group(struct sock *sk, struct ip_mreqn *imr)
memcpy(&iml->multi, imr, sizeof(*imr)); memcpy(&iml->multi, imr, sizeof(*imr));
iml->next_rcu = inet->mc_list; iml->next_rcu = inet->mc_list;
iml->sflist = NULL; iml->sflist = NULL;
iml->sfmode = MCAST_EXCLUDE; iml->sfmode = mode;
rcu_assign_pointer(inet->mc_list, iml); rcu_assign_pointer(inet->mc_list, iml);
ip_mc_inc_group(in_dev, addr); __ip_mc_inc_group(in_dev, addr, mode);
err = 0; err = 0;
done: done:
return err; return err;
} }
/* Join ASM (Any-Source Multicast) group
*/
int ip_mc_join_group(struct sock *sk, struct ip_mreqn *imr)
{
return __ip_mc_join_group(sk, imr, MCAST_EXCLUDE);
}
EXPORT_SYMBOL(ip_mc_join_group); EXPORT_SYMBOL(ip_mc_join_group);
/* Join SSM (Source-Specific Multicast) group
*/
int ip_mc_join_group_ssm(struct sock *sk, struct ip_mreqn *imr,
unsigned int mode)
{
return __ip_mc_join_group(sk, imr, mode);
}
static int ip_mc_leave_src(struct sock *sk, struct ip_mc_socklist *iml, static int ip_mc_leave_src(struct sock *sk, struct ip_mc_socklist *iml,
struct in_device *in_dev) struct in_device *in_dev)
{ {
......
...@@ -984,7 +984,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, ...@@ -984,7 +984,7 @@ static int do_ip_setsockopt(struct sock *sk, int level,
mreq.imr_multiaddr.s_addr = mreqs.imr_multiaddr; mreq.imr_multiaddr.s_addr = mreqs.imr_multiaddr;
mreq.imr_address.s_addr = mreqs.imr_interface; mreq.imr_address.s_addr = mreqs.imr_interface;
mreq.imr_ifindex = 0; mreq.imr_ifindex = 0;
err = ip_mc_join_group(sk, &mreq); err = ip_mc_join_group_ssm(sk, &mreq, MCAST_INCLUDE);
if (err && err != -EADDRINUSE) if (err && err != -EADDRINUSE)
break; break;
omode = MCAST_INCLUDE; omode = MCAST_INCLUDE;
...@@ -1061,7 +1061,7 @@ static int do_ip_setsockopt(struct sock *sk, int level, ...@@ -1061,7 +1061,7 @@ static int do_ip_setsockopt(struct sock *sk, int level,
mreq.imr_multiaddr = psin->sin_addr; mreq.imr_multiaddr = psin->sin_addr;
mreq.imr_address.s_addr = 0; mreq.imr_address.s_addr = 0;
mreq.imr_ifindex = greqs.gsr_interface; mreq.imr_ifindex = greqs.gsr_interface;
err = ip_mc_join_group(sk, &mreq); err = ip_mc_join_group_ssm(sk, &mreq, MCAST_INCLUDE);
if (err && err != -EADDRINUSE) if (err && err != -EADDRINUSE)
break; break;
greqs.gsr_interface = mreq.imr_ifindex; greqs.gsr_interface = mreq.imr_ifindex;
......
...@@ -729,8 +729,9 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname, ...@@ -729,8 +729,9 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
struct sockaddr_in6 *psin6; struct sockaddr_in6 *psin6;
psin6 = (struct sockaddr_in6 *)&greqs.gsr_group; psin6 = (struct sockaddr_in6 *)&greqs.gsr_group;
retv = ipv6_sock_mc_join(sk, greqs.gsr_interface, retv = ipv6_sock_mc_join_ssm(sk, greqs.gsr_interface,
&psin6->sin6_addr); &psin6->sin6_addr,
MCAST_INCLUDE);
/* prior join w/ different source is ok */ /* prior join w/ different source is ok */
if (retv && retv != -EADDRINUSE) if (retv && retv != -EADDRINUSE)
break; break;
......
...@@ -95,6 +95,8 @@ static int ip6_mc_add_src(struct inet6_dev *idev, const struct in6_addr *pmca, ...@@ -95,6 +95,8 @@ static int ip6_mc_add_src(struct inet6_dev *idev, const struct in6_addr *pmca,
int delta); int delta);
static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml, static int ip6_mc_leave_src(struct sock *sk, struct ipv6_mc_socklist *iml,
struct inet6_dev *idev); struct inet6_dev *idev);
static int __ipv6_dev_mc_inc(struct net_device *dev,
const struct in6_addr *addr, unsigned int mode);
#define MLD_QRV_DEFAULT 2 #define MLD_QRV_DEFAULT 2
/* RFC3810, 9.2. Query Interval */ /* RFC3810, 9.2. Query Interval */
...@@ -132,7 +134,8 @@ static int unsolicited_report_interval(struct inet6_dev *idev) ...@@ -132,7 +134,8 @@ static int unsolicited_report_interval(struct inet6_dev *idev)
return iv > 0 ? iv : 1; return iv > 0 ? iv : 1;
} }
int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr) static int __ipv6_sock_mc_join(struct sock *sk, int ifindex,
const struct in6_addr *addr, unsigned int mode)
{ {
struct net_device *dev = NULL; struct net_device *dev = NULL;
struct ipv6_mc_socklist *mc_lst; struct ipv6_mc_socklist *mc_lst;
...@@ -179,7 +182,7 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr) ...@@ -179,7 +182,7 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
} }
mc_lst->ifindex = dev->ifindex; mc_lst->ifindex = dev->ifindex;
mc_lst->sfmode = MCAST_EXCLUDE; mc_lst->sfmode = mode;
rwlock_init(&mc_lst->sflock); rwlock_init(&mc_lst->sflock);
mc_lst->sflist = NULL; mc_lst->sflist = NULL;
...@@ -187,7 +190,7 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr) ...@@ -187,7 +190,7 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
* now add/increase the group membership on the device * now add/increase the group membership on the device
*/ */
err = ipv6_dev_mc_inc(dev, addr); err = __ipv6_dev_mc_inc(dev, addr, mode);
if (err) { if (err) {
sock_kfree_s(sk, mc_lst, sizeof(*mc_lst)); sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
...@@ -199,8 +202,19 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr) ...@@ -199,8 +202,19 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
return 0; return 0;
} }
int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
{
return __ipv6_sock_mc_join(sk, ifindex, addr, MCAST_EXCLUDE);
}
EXPORT_SYMBOL(ipv6_sock_mc_join); EXPORT_SYMBOL(ipv6_sock_mc_join);
int ipv6_sock_mc_join_ssm(struct sock *sk, int ifindex,
const struct in6_addr *addr, unsigned int mode)
{
return __ipv6_sock_mc_join(sk, ifindex, addr, mode);
}
/* /*
* socket leave on multicast group * socket leave on multicast group
*/ */
...@@ -646,7 +660,7 @@ bool inet6_mc_check(struct sock *sk, const struct in6_addr *mc_addr, ...@@ -646,7 +660,7 @@ bool inet6_mc_check(struct sock *sk, const struct in6_addr *mc_addr,
return rv; return rv;
} }
static void igmp6_group_added(struct ifmcaddr6 *mc) static void igmp6_group_added(struct ifmcaddr6 *mc, unsigned int mode)
{ {
struct net_device *dev = mc->idev->dev; struct net_device *dev = mc->idev->dev;
char buf[MAX_ADDR_LEN]; char buf[MAX_ADDR_LEN];
...@@ -672,7 +686,13 @@ static void igmp6_group_added(struct ifmcaddr6 *mc) ...@@ -672,7 +686,13 @@ static void igmp6_group_added(struct ifmcaddr6 *mc)
} }
/* else v2 */ /* else v2 */
mc->mca_crcount = mc->idev->mc_qrv; /* Based on RFC3810 6.1, for newly added INCLUDE SSM, we
* should not send filter-mode change record as the mode
* should be from IN() to IN(A).
*/
if (mode == MCAST_EXCLUDE)
mc->mca_crcount = mc->idev->mc_qrv;
mld_ifc_event(mc->idev); mld_ifc_event(mc->idev);
} }
...@@ -770,13 +790,14 @@ static void mld_del_delrec(struct inet6_dev *idev, struct ifmcaddr6 *im) ...@@ -770,13 +790,14 @@ static void mld_del_delrec(struct inet6_dev *idev, struct ifmcaddr6 *im)
spin_lock_bh(&im->mca_lock); spin_lock_bh(&im->mca_lock);
if (pmc) { if (pmc) {
im->idev = pmc->idev; im->idev = pmc->idev;
im->mca_crcount = idev->mc_qrv;
im->mca_sfmode = pmc->mca_sfmode; im->mca_sfmode = pmc->mca_sfmode;
if (pmc->mca_sfmode == MCAST_INCLUDE) { if (pmc->mca_sfmode == MCAST_INCLUDE) {
im->mca_tomb = pmc->mca_tomb; im->mca_tomb = pmc->mca_tomb;
im->mca_sources = pmc->mca_sources; im->mca_sources = pmc->mca_sources;
for (psf = im->mca_sources; psf; psf = psf->sf_next) for (psf = im->mca_sources; psf; psf = psf->sf_next)
psf->sf_crcount = im->mca_crcount; psf->sf_crcount = idev->mc_qrv;
} else {
im->mca_crcount = idev->mc_qrv;
} }
in6_dev_put(pmc->idev); in6_dev_put(pmc->idev);
kfree(pmc); kfree(pmc);
...@@ -831,7 +852,8 @@ static void ma_put(struct ifmcaddr6 *mc) ...@@ -831,7 +852,8 @@ static void ma_put(struct ifmcaddr6 *mc)
} }
static struct ifmcaddr6 *mca_alloc(struct inet6_dev *idev, static struct ifmcaddr6 *mca_alloc(struct inet6_dev *idev,
const struct in6_addr *addr) const struct in6_addr *addr,
unsigned int mode)
{ {
struct ifmcaddr6 *mc; struct ifmcaddr6 *mc;
...@@ -849,9 +871,8 @@ static struct ifmcaddr6 *mca_alloc(struct inet6_dev *idev, ...@@ -849,9 +871,8 @@ static struct ifmcaddr6 *mca_alloc(struct inet6_dev *idev,
refcount_set(&mc->mca_refcnt, 1); refcount_set(&mc->mca_refcnt, 1);
spin_lock_init(&mc->mca_lock); spin_lock_init(&mc->mca_lock);
/* initial mode is (EX, empty) */ mc->mca_sfmode = mode;
mc->mca_sfmode = MCAST_EXCLUDE; mc->mca_sfcount[mode] = 1;
mc->mca_sfcount[MCAST_EXCLUDE] = 1;
if (ipv6_addr_is_ll_all_nodes(&mc->mca_addr) || if (ipv6_addr_is_ll_all_nodes(&mc->mca_addr) ||
IPV6_ADDR_MC_SCOPE(&mc->mca_addr) < IPV6_ADDR_SCOPE_LINKLOCAL) IPV6_ADDR_MC_SCOPE(&mc->mca_addr) < IPV6_ADDR_SCOPE_LINKLOCAL)
...@@ -863,7 +884,8 @@ static struct ifmcaddr6 *mca_alloc(struct inet6_dev *idev, ...@@ -863,7 +884,8 @@ static struct ifmcaddr6 *mca_alloc(struct inet6_dev *idev,
/* /*
* device multicast group inc (add if not found) * device multicast group inc (add if not found)
*/ */
int ipv6_dev_mc_inc(struct net_device *dev, const struct in6_addr *addr) static int __ipv6_dev_mc_inc(struct net_device *dev,
const struct in6_addr *addr, unsigned int mode)
{ {
struct ifmcaddr6 *mc; struct ifmcaddr6 *mc;
struct inet6_dev *idev; struct inet6_dev *idev;
...@@ -887,14 +909,13 @@ int ipv6_dev_mc_inc(struct net_device *dev, const struct in6_addr *addr) ...@@ -887,14 +909,13 @@ int ipv6_dev_mc_inc(struct net_device *dev, const struct in6_addr *addr)
if (ipv6_addr_equal(&mc->mca_addr, addr)) { if (ipv6_addr_equal(&mc->mca_addr, addr)) {
mc->mca_users++; mc->mca_users++;
write_unlock_bh(&idev->lock); write_unlock_bh(&idev->lock);
ip6_mc_add_src(idev, &mc->mca_addr, MCAST_EXCLUDE, 0, ip6_mc_add_src(idev, &mc->mca_addr, mode, 0, NULL, 0);
NULL, 0);
in6_dev_put(idev); in6_dev_put(idev);
return 0; return 0;
} }
} }
mc = mca_alloc(idev, addr); mc = mca_alloc(idev, addr, mode);
if (!mc) { if (!mc) {
write_unlock_bh(&idev->lock); write_unlock_bh(&idev->lock);
in6_dev_put(idev); in6_dev_put(idev);
...@@ -911,11 +932,16 @@ int ipv6_dev_mc_inc(struct net_device *dev, const struct in6_addr *addr) ...@@ -911,11 +932,16 @@ int ipv6_dev_mc_inc(struct net_device *dev, const struct in6_addr *addr)
write_unlock_bh(&idev->lock); write_unlock_bh(&idev->lock);
mld_del_delrec(idev, mc); mld_del_delrec(idev, mc);
igmp6_group_added(mc); igmp6_group_added(mc, mode);
ma_put(mc); ma_put(mc);
return 0; return 0;
} }
int ipv6_dev_mc_inc(struct net_device *dev, const struct in6_addr *addr)
{
return __ipv6_dev_mc_inc(dev, addr, MCAST_EXCLUDE);
}
/* /*
* device multicast group del * device multicast group del
*/ */
...@@ -1751,7 +1777,7 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc, ...@@ -1751,7 +1777,7 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc,
psf_next = psf->sf_next; psf_next = psf->sf_next;
if (!is_in(pmc, psf, type, gdeleted, sdeleted)) { if (!is_in(pmc, psf, type, gdeleted, sdeleted) && !crsend) {
psf_prev = psf; psf_prev = psf;
continue; continue;
} }
...@@ -2066,7 +2092,7 @@ static void mld_send_initial_cr(struct inet6_dev *idev) ...@@ -2066,7 +2092,7 @@ static void mld_send_initial_cr(struct inet6_dev *idev)
if (pmc->mca_sfcount[MCAST_EXCLUDE]) if (pmc->mca_sfcount[MCAST_EXCLUDE])
type = MLD2_CHANGE_TO_EXCLUDE; type = MLD2_CHANGE_TO_EXCLUDE;
else else
type = MLD2_CHANGE_TO_INCLUDE; type = MLD2_ALLOW_NEW_SOURCES;
skb = add_grec(skb, pmc, type, 0, 0, 1); skb = add_grec(skb, pmc, type, 0, 0, 1);
spin_unlock_bh(&pmc->mca_lock); spin_unlock_bh(&pmc->mca_lock);
} }
...@@ -2546,7 +2572,7 @@ void ipv6_mc_up(struct inet6_dev *idev) ...@@ -2546,7 +2572,7 @@ void ipv6_mc_up(struct inet6_dev *idev)
ipv6_mc_reset(idev); ipv6_mc_reset(idev);
for (i = idev->mc_list; i; i = i->next) { for (i = idev->mc_list; i; i = i->next) {
mld_del_delrec(idev, i); mld_del_delrec(idev, i);
igmp6_group_added(i); igmp6_group_added(i, i->mca_sfmode);
} }
read_unlock_bh(&idev->lock); read_unlock_bh(&idev->lock);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment