Skip to content

Commit 24803f3

Browse files
liuhangbindavem330
authored andcommitted
igmp: do not remove igmp souce list info when set link down
In commit 24cf3af ("igmp: call ip_mc_clear_src..."), we forgot to remove igmpv3_clear_delrec() in ip_mc_down(), which also called ip_mc_clear_src(). This make us clear all IGMPv3 source filter info after NETDEV_DOWN. Move igmpv3_clear_delrec() to ip_mc_destroy_dev() and then no need ip_mc_clear_src() in ip_mc_destroy_dev(). On the other hand, we should restore back instead of free all source filter info in igmpv3_del_delrec(). Or we will not able to restore IGMPv3 source filter info after NETDEV_UP and NETDEV_POST_TYPE_CHANGE. Fixes: 24cf3af ("igmp: call ip_mc_clear_src() only when ...") Signed-off-by: Hangbin Liu <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent f6c365f commit 24803f3

File tree

1 file changed

+36
-14
lines changed

1 file changed

+36
-14
lines changed

net/ipv4/igmp.c

Lines changed: 36 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ static int unsolicited_report_interval(struct in_device *in_dev)
162162
}
163163

164164
static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im);
165-
static void igmpv3_del_delrec(struct in_device *in_dev, __be32 multiaddr);
165+
static void igmpv3_del_delrec(struct in_device *in_dev, struct ip_mc_list *im);
166166
static void igmpv3_clear_delrec(struct in_device *in_dev);
167167
static int sf_setstate(struct ip_mc_list *pmc);
168168
static void sf_markstate(struct ip_mc_list *pmc);
@@ -1130,10 +1130,15 @@ static void igmpv3_add_delrec(struct in_device *in_dev, struct ip_mc_list *im)
11301130
spin_unlock_bh(&in_dev->mc_tomb_lock);
11311131
}
11321132

1133-
static void igmpv3_del_delrec(struct in_device *in_dev, __be32 multiaddr)
1133+
/*
1134+
* restore ip_mc_list deleted records
1135+
*/
1136+
static void igmpv3_del_delrec(struct in_device *in_dev, struct ip_mc_list *im)
11341137
{
11351138
struct ip_mc_list *pmc, *pmc_prev;
1136-
struct ip_sf_list *psf, *psf_next;
1139+
struct ip_sf_list *psf;
1140+
struct net *net = dev_net(in_dev->dev);
1141+
__be32 multiaddr = im->multiaddr;
11371142

11381143
spin_lock_bh(&in_dev->mc_tomb_lock);
11391144
pmc_prev = NULL;
@@ -1149,16 +1154,26 @@ static void igmpv3_del_delrec(struct in_device *in_dev, __be32 multiaddr)
11491154
in_dev->mc_tomb = pmc->next;
11501155
}
11511156
spin_unlock_bh(&in_dev->mc_tomb_lock);
1157+
1158+
spin_lock_bh(&im->lock);
11521159
if (pmc) {
1153-
for (psf = pmc->tomb; psf; psf = psf_next) {
1154-
psf_next = psf->sf_next;
1155-
kfree(psf);
1160+
im->interface = pmc->interface;
1161+
im->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
1162+
im->sfmode = pmc->sfmode;
1163+
if (pmc->sfmode == MCAST_INCLUDE) {
1164+
im->tomb = pmc->tomb;
1165+
im->sources = pmc->sources;
1166+
for (psf = im->sources; psf; psf = psf->sf_next)
1167+
psf->sf_crcount = im->crcount;
11561168
}
11571169
in_dev_put(pmc->interface);
1158-
kfree(pmc);
11591170
}
1171+
spin_unlock_bh(&im->lock);
11601172
}
11611173

1174+
/*
1175+
* flush ip_mc_list deleted records
1176+
*/
11621177
static void igmpv3_clear_delrec(struct in_device *in_dev)
11631178
{
11641179
struct ip_mc_list *pmc, *nextpmc;
@@ -1366,7 +1381,7 @@ void ip_mc_inc_group(struct in_device *in_dev, __be32 addr)
13661381
ip_mc_hash_add(in_dev, im);
13671382

13681383
#ifdef CONFIG_IP_MULTICAST
1369-
igmpv3_del_delrec(in_dev, im->multiaddr);
1384+
igmpv3_del_delrec(in_dev, im);
13701385
#endif
13711386
igmp_group_added(im);
13721387
if (!in_dev->dead)
@@ -1626,8 +1641,12 @@ void ip_mc_remap(struct in_device *in_dev)
16261641

16271642
ASSERT_RTNL();
16281643

1629-
for_each_pmc_rtnl(in_dev, pmc)
1644+
for_each_pmc_rtnl(in_dev, pmc) {
1645+
#ifdef CONFIG_IP_MULTICAST
1646+
igmpv3_del_delrec(in_dev, pmc);
1647+
#endif
16301648
igmp_group_added(pmc);
1649+
}
16311650
}
16321651

16331652
/* Device going down */
@@ -1648,7 +1667,6 @@ void ip_mc_down(struct in_device *in_dev)
16481667
in_dev->mr_gq_running = 0;
16491668
if (del_timer(&in_dev->mr_gq_timer))
16501669
__in_dev_put(in_dev);
1651-
igmpv3_clear_delrec(in_dev);
16521670
#endif
16531671

16541672
ip_mc_dec_group(in_dev, IGMP_ALL_HOSTS);
@@ -1688,8 +1706,12 @@ void ip_mc_up(struct in_device *in_dev)
16881706
#endif
16891707
ip_mc_inc_group(in_dev, IGMP_ALL_HOSTS);
16901708

1691-
for_each_pmc_rtnl(in_dev, pmc)
1709+
for_each_pmc_rtnl(in_dev, pmc) {
1710+
#ifdef CONFIG_IP_MULTICAST
1711+
igmpv3_del_delrec(in_dev, pmc);
1712+
#endif
16921713
igmp_group_added(pmc);
1714+
}
16931715
}
16941716

16951717
/*
@@ -1704,13 +1726,13 @@ void ip_mc_destroy_dev(struct in_device *in_dev)
17041726

17051727
/* Deactivate timers */
17061728
ip_mc_down(in_dev);
1729+
#ifdef CONFIG_IP_MULTICAST
1730+
igmpv3_clear_delrec(in_dev);
1731+
#endif
17071732

17081733
while ((i = rtnl_dereference(in_dev->mc_list)) != NULL) {
17091734
in_dev->mc_list = i->next_rcu;
17101735
in_dev->mc_count--;
1711-
1712-
/* We've dropped the groups in ip_mc_down already */
1713-
ip_mc_clear_src(i);
17141736
ip_ma_put(i);
17151737
}
17161738
}

0 commit comments

Comments
 (0)