|
@@ -635,6 +635,24 @@ static void igmpv3_clear_zeros(struct ip_sf_list **ppsf)
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+static void ip_sf_list_clear_all(struct ip_sf_list *psf)
|
|
|
|
|
+{
|
|
|
|
|
+ struct ip_sf_list *next;
|
|
|
|
|
+
|
|
|
|
|
+ while (psf) {
|
|
|
|
|
+ next = psf->sf_next;
|
|
|
|
|
+ kfree(psf);
|
|
|
|
|
+ psf = next;
|
|
|
|
|
+ }
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
|
|
+static void kfree_pmc(struct ip_mc_list *pmc)
|
|
|
|
|
+{
|
|
|
|
|
+ ip_sf_list_clear_all(pmc->sources);
|
|
|
|
|
+ ip_sf_list_clear_all(pmc->tomb);
|
|
|
|
|
+ kfree(pmc);
|
|
|
|
|
+}
|
|
|
|
|
+
|
|
|
static void igmpv3_send_cr(struct in_device *in_dev)
|
|
static void igmpv3_send_cr(struct in_device *in_dev)
|
|
|
{
|
|
{
|
|
|
struct ip_mc_list *pmc, *pmc_prev, *pmc_next;
|
|
struct ip_mc_list *pmc, *pmc_prev, *pmc_next;
|
|
@@ -671,7 +689,7 @@ static void igmpv3_send_cr(struct in_device *in_dev)
|
|
|
else
|
|
else
|
|
|
in_dev->mc_tomb = pmc_next;
|
|
in_dev->mc_tomb = pmc_next;
|
|
|
in_dev_put(pmc->interface);
|
|
in_dev_put(pmc->interface);
|
|
|
- kfree(pmc);
|
|
|
|
|
|
|
+ kfree_pmc(pmc);
|
|
|
} else
|
|
} else
|
|
|
pmc_prev = pmc;
|
|
pmc_prev = pmc;
|
|
|
}
|
|
}
|
|
@@ -1201,14 +1219,18 @@ static void igmpv3_del_delrec(struct in_device *in_dev, struct ip_mc_list *im)
|
|
|
im->interface = pmc->interface;
|
|
im->interface = pmc->interface;
|
|
|
if (im->sfmode == MCAST_INCLUDE) {
|
|
if (im->sfmode == MCAST_INCLUDE) {
|
|
|
im->tomb = pmc->tomb;
|
|
im->tomb = pmc->tomb;
|
|
|
|
|
+ pmc->tomb = NULL;
|
|
|
|
|
+
|
|
|
im->sources = pmc->sources;
|
|
im->sources = pmc->sources;
|
|
|
|
|
+ pmc->sources = NULL;
|
|
|
|
|
+
|
|
|
for (psf = im->sources; psf; psf = psf->sf_next)
|
|
for (psf = im->sources; psf; psf = psf->sf_next)
|
|
|
psf->sf_crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
|
|
psf->sf_crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
|
|
|
} else {
|
|
} else {
|
|
|
im->crcount = in_dev->mr_qrv ?: net->ipv4.sysctl_igmp_qrv;
|
|
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(pmc);
|
|
|
}
|
|
}
|
|
|
spin_unlock_bh(&im->lock);
|
|
spin_unlock_bh(&im->lock);
|
|
|
}
|
|
}
|
|
@@ -1229,21 +1251,18 @@ static void igmpv3_clear_delrec(struct in_device *in_dev)
|
|
|
nextpmc = pmc->next;
|
|
nextpmc = pmc->next;
|
|
|
ip_mc_clear_src(pmc);
|
|
ip_mc_clear_src(pmc);
|
|
|
in_dev_put(pmc->interface);
|
|
in_dev_put(pmc->interface);
|
|
|
- kfree(pmc);
|
|
|
|
|
|
|
+ kfree_pmc(pmc);
|
|
|
}
|
|
}
|
|
|
/* clear dead sources, too */
|
|
/* clear dead sources, too */
|
|
|
rcu_read_lock();
|
|
rcu_read_lock();
|
|
|
for_each_pmc_rcu(in_dev, pmc) {
|
|
for_each_pmc_rcu(in_dev, pmc) {
|
|
|
- struct ip_sf_list *psf, *psf_next;
|
|
|
|
|
|
|
+ struct ip_sf_list *psf;
|
|
|
|
|
|
|
|
spin_lock_bh(&pmc->lock);
|
|
spin_lock_bh(&pmc->lock);
|
|
|
psf = pmc->tomb;
|
|
psf = pmc->tomb;
|
|
|
pmc->tomb = NULL;
|
|
pmc->tomb = NULL;
|
|
|
spin_unlock_bh(&pmc->lock);
|
|
spin_unlock_bh(&pmc->lock);
|
|
|
- for (; psf; psf = psf_next) {
|
|
|
|
|
- psf_next = psf->sf_next;
|
|
|
|
|
- kfree(psf);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ ip_sf_list_clear_all(psf);
|
|
|
}
|
|
}
|
|
|
rcu_read_unlock();
|
|
rcu_read_unlock();
|
|
|
}
|
|
}
|
|
@@ -2114,7 +2133,7 @@ static int ip_mc_add_src(struct in_device *in_dev, __be32 *pmca, int sfmode,
|
|
|
|
|
|
|
|
static void ip_mc_clear_src(struct ip_mc_list *pmc)
|
|
static void ip_mc_clear_src(struct ip_mc_list *pmc)
|
|
|
{
|
|
{
|
|
|
- struct ip_sf_list *psf, *nextpsf, *tomb, *sources;
|
|
|
|
|
|
|
+ struct ip_sf_list *tomb, *sources;
|
|
|
|
|
|
|
|
spin_lock_bh(&pmc->lock);
|
|
spin_lock_bh(&pmc->lock);
|
|
|
tomb = pmc->tomb;
|
|
tomb = pmc->tomb;
|
|
@@ -2126,14 +2145,8 @@ static void ip_mc_clear_src(struct ip_mc_list *pmc)
|
|
|
pmc->sfcount[MCAST_EXCLUDE] = 1;
|
|
pmc->sfcount[MCAST_EXCLUDE] = 1;
|
|
|
spin_unlock_bh(&pmc->lock);
|
|
spin_unlock_bh(&pmc->lock);
|
|
|
|
|
|
|
|
- for (psf = tomb; psf; psf = nextpsf) {
|
|
|
|
|
- nextpsf = psf->sf_next;
|
|
|
|
|
- kfree(psf);
|
|
|
|
|
- }
|
|
|
|
|
- for (psf = sources; psf; psf = nextpsf) {
|
|
|
|
|
- nextpsf = psf->sf_next;
|
|
|
|
|
- kfree(psf);
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ ip_sf_list_clear_all(tomb);
|
|
|
|
|
+ ip_sf_list_clear_all(sources);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/* Join a multicast group
|
|
/* Join a multicast group
|