mirror of
https://github.com/Fishwaldo/Star64_linux.git
synced 2025-04-01 12:04:08 +00:00
ipv6: mcast: RCU conversions
- ipv6_sock_mc_join() : doesnt touch dev refcount - ipv6_sock_mc_drop() : doesnt touch dev/idev refcounts - ip6_mc_find_dev() becomes ip6_mc_find_dev_rcu() (called from rcu), and doesnt touch dev/idev refcounts - ipv6_sock_mc_close() : doesnt touch dev/idev refcounts - ip6_mc_source() uses ip6_mc_find_dev_rcu() - ip6_mc_msfilter() uses ip6_mc_find_dev_rcu() - ip6_mc_msfget() uses ip6_mc_find_dev_rcu() - ipv6_dev_mc_dec(), ipv6_chk_mcast_addr(), igmp6_event_query(), igmp6_event_report(), mld_sendpack(), igmp6_send() dont touch idev refcount Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
97859160c5
commit
96b52e61be
1 changed files with 87 additions and 96 deletions
183
net/ipv6/mcast.c
183
net/ipv6/mcast.c
|
@ -152,18 +152,19 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
|
||||||
mc_lst->next = NULL;
|
mc_lst->next = NULL;
|
||||||
ipv6_addr_copy(&mc_lst->addr, addr);
|
ipv6_addr_copy(&mc_lst->addr, addr);
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
if (ifindex == 0) {
|
if (ifindex == 0) {
|
||||||
struct rt6_info *rt;
|
struct rt6_info *rt;
|
||||||
rt = rt6_lookup(net, addr, NULL, 0, 0);
|
rt = rt6_lookup(net, addr, NULL, 0, 0);
|
||||||
if (rt) {
|
if (rt) {
|
||||||
dev = rt->rt6i_dev;
|
dev = rt->rt6i_dev;
|
||||||
dev_hold(dev);
|
|
||||||
dst_release(&rt->u.dst);
|
dst_release(&rt->u.dst);
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
dev = dev_get_by_index(net, ifindex);
|
dev = dev_get_by_index_rcu(net, ifindex);
|
||||||
|
|
||||||
if (dev == NULL) {
|
if (dev == NULL) {
|
||||||
|
rcu_read_unlock();
|
||||||
sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
|
sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
}
|
}
|
||||||
|
@ -180,8 +181,8 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
|
||||||
err = ipv6_dev_mc_inc(dev, addr);
|
err = ipv6_dev_mc_inc(dev, addr);
|
||||||
|
|
||||||
if (err) {
|
if (err) {
|
||||||
|
rcu_read_unlock();
|
||||||
sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
|
sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
|
||||||
dev_put(dev);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -190,7 +191,7 @@ int ipv6_sock_mc_join(struct sock *sk, int ifindex, const struct in6_addr *addr)
|
||||||
np->ipv6_mc_list = mc_lst;
|
np->ipv6_mc_list = mc_lst;
|
||||||
write_unlock_bh(&ipv6_sk_mc_lock);
|
write_unlock_bh(&ipv6_sk_mc_lock);
|
||||||
|
|
||||||
dev_put(dev);
|
rcu_read_unlock();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -213,18 +214,17 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr)
|
||||||
*lnk = mc_lst->next;
|
*lnk = mc_lst->next;
|
||||||
write_unlock_bh(&ipv6_sk_mc_lock);
|
write_unlock_bh(&ipv6_sk_mc_lock);
|
||||||
|
|
||||||
dev = dev_get_by_index(net, mc_lst->ifindex);
|
rcu_read_lock();
|
||||||
|
dev = dev_get_by_index_rcu(net, mc_lst->ifindex);
|
||||||
if (dev != NULL) {
|
if (dev != NULL) {
|
||||||
struct inet6_dev *idev = in6_dev_get(dev);
|
struct inet6_dev *idev = __in6_dev_get(dev);
|
||||||
|
|
||||||
(void) ip6_mc_leave_src(sk, mc_lst, idev);
|
(void) ip6_mc_leave_src(sk, mc_lst, idev);
|
||||||
if (idev) {
|
if (idev)
|
||||||
__ipv6_dev_mc_dec(idev, &mc_lst->addr);
|
__ipv6_dev_mc_dec(idev, &mc_lst->addr);
|
||||||
in6_dev_put(idev);
|
|
||||||
}
|
|
||||||
dev_put(dev);
|
|
||||||
} else
|
} else
|
||||||
(void) ip6_mc_leave_src(sk, mc_lst, NULL);
|
(void) ip6_mc_leave_src(sk, mc_lst, NULL);
|
||||||
|
rcu_read_unlock();
|
||||||
sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
|
sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -234,43 +234,36 @@ int ipv6_sock_mc_drop(struct sock *sk, int ifindex, const struct in6_addr *addr)
|
||||||
return -EADDRNOTAVAIL;
|
return -EADDRNOTAVAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct inet6_dev *ip6_mc_find_dev(struct net *net,
|
/* called with rcu_read_lock() */
|
||||||
struct in6_addr *group,
|
static struct inet6_dev *ip6_mc_find_dev_rcu(struct net *net,
|
||||||
int ifindex)
|
struct in6_addr *group,
|
||||||
|
int ifindex)
|
||||||
{
|
{
|
||||||
struct net_device *dev = NULL;
|
struct net_device *dev = NULL;
|
||||||
struct inet6_dev *idev = NULL;
|
struct inet6_dev *idev = NULL;
|
||||||
|
|
||||||
if (ifindex == 0) {
|
if (ifindex == 0) {
|
||||||
struct rt6_info *rt;
|
struct rt6_info *rt = rt6_lookup(net, group, NULL, 0, 0);
|
||||||
|
|
||||||
rt = rt6_lookup(net, group, NULL, 0, 0);
|
|
||||||
if (rt) {
|
if (rt) {
|
||||||
dev = rt->rt6i_dev;
|
dev = rt->rt6i_dev;
|
||||||
dev_hold(dev);
|
dev_hold(dev);
|
||||||
dst_release(&rt->u.dst);
|
dst_release(&rt->u.dst);
|
||||||
}
|
}
|
||||||
} else
|
} else
|
||||||
dev = dev_get_by_index(net, ifindex);
|
dev = dev_get_by_index_rcu(net, ifindex);
|
||||||
|
|
||||||
if (!dev)
|
if (!dev)
|
||||||
goto nodev;
|
return NULL;
|
||||||
idev = in6_dev_get(dev);
|
idev = __in6_dev_get(dev);
|
||||||
if (!idev)
|
if (!idev)
|
||||||
goto release;
|
return NULL;;
|
||||||
read_lock_bh(&idev->lock);
|
read_lock_bh(&idev->lock);
|
||||||
if (idev->dead)
|
if (idev->dead) {
|
||||||
goto unlock_release;
|
read_unlock_bh(&idev->lock);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
return idev;
|
return idev;
|
||||||
|
|
||||||
unlock_release:
|
|
||||||
read_unlock_bh(&idev->lock);
|
|
||||||
in6_dev_put(idev);
|
|
||||||
release:
|
|
||||||
dev_put(dev);
|
|
||||||
nodev:
|
|
||||||
return NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ipv6_sock_mc_close(struct sock *sk)
|
void ipv6_sock_mc_close(struct sock *sk)
|
||||||
|
@ -286,19 +279,17 @@ void ipv6_sock_mc_close(struct sock *sk)
|
||||||
np->ipv6_mc_list = mc_lst->next;
|
np->ipv6_mc_list = mc_lst->next;
|
||||||
write_unlock_bh(&ipv6_sk_mc_lock);
|
write_unlock_bh(&ipv6_sk_mc_lock);
|
||||||
|
|
||||||
dev = dev_get_by_index(net, mc_lst->ifindex);
|
rcu_read_lock();
|
||||||
|
dev = dev_get_by_index_rcu(net, mc_lst->ifindex);
|
||||||
if (dev) {
|
if (dev) {
|
||||||
struct inet6_dev *idev = in6_dev_get(dev);
|
struct inet6_dev *idev = __in6_dev_get(dev);
|
||||||
|
|
||||||
(void) ip6_mc_leave_src(sk, mc_lst, idev);
|
(void) ip6_mc_leave_src(sk, mc_lst, idev);
|
||||||
if (idev) {
|
if (idev)
|
||||||
__ipv6_dev_mc_dec(idev, &mc_lst->addr);
|
__ipv6_dev_mc_dec(idev, &mc_lst->addr);
|
||||||
in6_dev_put(idev);
|
|
||||||
}
|
|
||||||
dev_put(dev);
|
|
||||||
} else
|
} else
|
||||||
(void) ip6_mc_leave_src(sk, mc_lst, NULL);
|
(void) ip6_mc_leave_src(sk, mc_lst, NULL);
|
||||||
|
rcu_read_unlock();
|
||||||
sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
|
sock_kfree_s(sk, mc_lst, sizeof(*mc_lst));
|
||||||
|
|
||||||
write_lock_bh(&ipv6_sk_mc_lock);
|
write_lock_bh(&ipv6_sk_mc_lock);
|
||||||
|
@ -327,14 +318,17 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
|
||||||
if (!ipv6_addr_is_multicast(group))
|
if (!ipv6_addr_is_multicast(group))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
idev = ip6_mc_find_dev(net, group, pgsr->gsr_interface);
|
rcu_read_lock();
|
||||||
if (!idev)
|
idev = ip6_mc_find_dev_rcu(net, group, pgsr->gsr_interface);
|
||||||
|
if (!idev) {
|
||||||
|
rcu_read_unlock();
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
}
|
||||||
dev = idev->dev;
|
dev = idev->dev;
|
||||||
|
|
||||||
err = -EADDRNOTAVAIL;
|
err = -EADDRNOTAVAIL;
|
||||||
|
|
||||||
read_lock_bh(&ipv6_sk_mc_lock);
|
read_lock(&ipv6_sk_mc_lock);
|
||||||
for (pmc=inet6->ipv6_mc_list; pmc; pmc=pmc->next) {
|
for (pmc=inet6->ipv6_mc_list; pmc; pmc=pmc->next) {
|
||||||
if (pgsr->gsr_interface && pmc->ifindex != pgsr->gsr_interface)
|
if (pgsr->gsr_interface && pmc->ifindex != pgsr->gsr_interface)
|
||||||
continue;
|
continue;
|
||||||
|
@ -358,7 +352,7 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
|
||||||
pmc->sfmode = omode;
|
pmc->sfmode = omode;
|
||||||
}
|
}
|
||||||
|
|
||||||
write_lock_bh(&pmc->sflock);
|
write_lock(&pmc->sflock);
|
||||||
pmclocked = 1;
|
pmclocked = 1;
|
||||||
|
|
||||||
psl = pmc->sflist;
|
psl = pmc->sflist;
|
||||||
|
@ -433,11 +427,10 @@ int ip6_mc_source(int add, int omode, struct sock *sk,
|
||||||
ip6_mc_add_src(idev, group, omode, 1, source, 1);
|
ip6_mc_add_src(idev, group, omode, 1, source, 1);
|
||||||
done:
|
done:
|
||||||
if (pmclocked)
|
if (pmclocked)
|
||||||
write_unlock_bh(&pmc->sflock);
|
write_unlock(&pmc->sflock);
|
||||||
read_unlock_bh(&ipv6_sk_mc_lock);
|
read_unlock(&ipv6_sk_mc_lock);
|
||||||
read_unlock_bh(&idev->lock);
|
read_unlock_bh(&idev->lock);
|
||||||
in6_dev_put(idev);
|
rcu_read_unlock();
|
||||||
dev_put(dev);
|
|
||||||
if (leavegroup)
|
if (leavegroup)
|
||||||
return ipv6_sock_mc_drop(sk, pgsr->gsr_interface, group);
|
return ipv6_sock_mc_drop(sk, pgsr->gsr_interface, group);
|
||||||
return err;
|
return err;
|
||||||
|
@ -463,14 +456,17 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf)
|
||||||
gsf->gf_fmode != MCAST_EXCLUDE)
|
gsf->gf_fmode != MCAST_EXCLUDE)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
idev = ip6_mc_find_dev(net, group, gsf->gf_interface);
|
rcu_read_lock();
|
||||||
|
idev = ip6_mc_find_dev_rcu(net, group, gsf->gf_interface);
|
||||||
|
|
||||||
if (!idev)
|
if (!idev) {
|
||||||
|
rcu_read_unlock();
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
}
|
||||||
dev = idev->dev;
|
dev = idev->dev;
|
||||||
|
|
||||||
err = 0;
|
err = 0;
|
||||||
read_lock_bh(&ipv6_sk_mc_lock);
|
read_lock(&ipv6_sk_mc_lock);
|
||||||
|
|
||||||
if (gsf->gf_fmode == MCAST_INCLUDE && gsf->gf_numsrc == 0) {
|
if (gsf->gf_fmode == MCAST_INCLUDE && gsf->gf_numsrc == 0) {
|
||||||
leavegroup = 1;
|
leavegroup = 1;
|
||||||
|
@ -512,7 +508,7 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf)
|
||||||
(void) ip6_mc_add_src(idev, group, gsf->gf_fmode, 0, NULL, 0);
|
(void) ip6_mc_add_src(idev, group, gsf->gf_fmode, 0, NULL, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
write_lock_bh(&pmc->sflock);
|
write_lock(&pmc->sflock);
|
||||||
psl = pmc->sflist;
|
psl = pmc->sflist;
|
||||||
if (psl) {
|
if (psl) {
|
||||||
(void) ip6_mc_del_src(idev, group, pmc->sfmode,
|
(void) ip6_mc_del_src(idev, group, pmc->sfmode,
|
||||||
|
@ -522,13 +518,12 @@ int ip6_mc_msfilter(struct sock *sk, struct group_filter *gsf)
|
||||||
(void) ip6_mc_del_src(idev, group, pmc->sfmode, 0, NULL, 0);
|
(void) ip6_mc_del_src(idev, group, pmc->sfmode, 0, NULL, 0);
|
||||||
pmc->sflist = newpsl;
|
pmc->sflist = newpsl;
|
||||||
pmc->sfmode = gsf->gf_fmode;
|
pmc->sfmode = gsf->gf_fmode;
|
||||||
write_unlock_bh(&pmc->sflock);
|
write_unlock(&pmc->sflock);
|
||||||
err = 0;
|
err = 0;
|
||||||
done:
|
done:
|
||||||
read_unlock_bh(&ipv6_sk_mc_lock);
|
read_unlock(&ipv6_sk_mc_lock);
|
||||||
read_unlock_bh(&idev->lock);
|
read_unlock_bh(&idev->lock);
|
||||||
in6_dev_put(idev);
|
rcu_read_unlock();
|
||||||
dev_put(dev);
|
|
||||||
if (leavegroup)
|
if (leavegroup)
|
||||||
err = ipv6_sock_mc_drop(sk, gsf->gf_interface, group);
|
err = ipv6_sock_mc_drop(sk, gsf->gf_interface, group);
|
||||||
return err;
|
return err;
|
||||||
|
@ -551,11 +546,13 @@ int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,
|
||||||
if (!ipv6_addr_is_multicast(group))
|
if (!ipv6_addr_is_multicast(group))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
idev = ip6_mc_find_dev(net, group, gsf->gf_interface);
|
rcu_read_lock();
|
||||||
|
idev = ip6_mc_find_dev_rcu(net, group, gsf->gf_interface);
|
||||||
|
|
||||||
if (!idev)
|
if (!idev) {
|
||||||
|
rcu_read_unlock();
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
}
|
||||||
dev = idev->dev;
|
dev = idev->dev;
|
||||||
|
|
||||||
err = -EADDRNOTAVAIL;
|
err = -EADDRNOTAVAIL;
|
||||||
|
@ -577,8 +574,7 @@ int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,
|
||||||
psl = pmc->sflist;
|
psl = pmc->sflist;
|
||||||
count = psl ? psl->sl_count : 0;
|
count = psl ? psl->sl_count : 0;
|
||||||
read_unlock_bh(&idev->lock);
|
read_unlock_bh(&idev->lock);
|
||||||
in6_dev_put(idev);
|
rcu_read_unlock();
|
||||||
dev_put(dev);
|
|
||||||
|
|
||||||
copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc;
|
copycount = count < gsf->gf_numsrc ? count : gsf->gf_numsrc;
|
||||||
gsf->gf_numsrc = count;
|
gsf->gf_numsrc = count;
|
||||||
|
@ -604,8 +600,7 @@ int ip6_mc_msfget(struct sock *sk, struct group_filter *gsf,
|
||||||
return 0;
|
return 0;
|
||||||
done:
|
done:
|
||||||
read_unlock_bh(&idev->lock);
|
read_unlock_bh(&idev->lock);
|
||||||
in6_dev_put(idev);
|
rcu_read_unlock();
|
||||||
dev_put(dev);
|
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -822,6 +817,7 @@ int ipv6_dev_mc_inc(struct net_device *dev, const struct in6_addr *addr)
|
||||||
struct ifmcaddr6 *mc;
|
struct ifmcaddr6 *mc;
|
||||||
struct inet6_dev *idev;
|
struct inet6_dev *idev;
|
||||||
|
|
||||||
|
/* we need to take a reference on idev */
|
||||||
idev = in6_dev_get(dev);
|
idev = in6_dev_get(dev);
|
||||||
|
|
||||||
if (idev == NULL)
|
if (idev == NULL)
|
||||||
|
@ -860,7 +856,7 @@ int ipv6_dev_mc_inc(struct net_device *dev, const struct in6_addr *addr)
|
||||||
setup_timer(&mc->mca_timer, igmp6_timer_handler, (unsigned long)mc);
|
setup_timer(&mc->mca_timer, igmp6_timer_handler, (unsigned long)mc);
|
||||||
|
|
||||||
ipv6_addr_copy(&mc->mca_addr, addr);
|
ipv6_addr_copy(&mc->mca_addr, addr);
|
||||||
mc->idev = idev;
|
mc->idev = idev; /* (reference taken) */
|
||||||
mc->mca_users = 1;
|
mc->mca_users = 1;
|
||||||
/* mca_stamp should be updated upon changes */
|
/* mca_stamp should be updated upon changes */
|
||||||
mc->mca_cstamp = mc->mca_tstamp = jiffies;
|
mc->mca_cstamp = mc->mca_tstamp = jiffies;
|
||||||
|
@ -915,16 +911,18 @@ int __ipv6_dev_mc_dec(struct inet6_dev *idev, const struct in6_addr *addr)
|
||||||
|
|
||||||
int ipv6_dev_mc_dec(struct net_device *dev, const struct in6_addr *addr)
|
int ipv6_dev_mc_dec(struct net_device *dev, const struct in6_addr *addr)
|
||||||
{
|
{
|
||||||
struct inet6_dev *idev = in6_dev_get(dev);
|
struct inet6_dev *idev;
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
|
||||||
|
idev = __in6_dev_get(dev);
|
||||||
if (!idev)
|
if (!idev)
|
||||||
return -ENODEV;
|
err = -ENODEV;
|
||||||
|
else
|
||||||
err = __ipv6_dev_mc_dec(idev, addr);
|
err = __ipv6_dev_mc_dec(idev, addr);
|
||||||
|
|
||||||
in6_dev_put(idev);
|
|
||||||
|
|
||||||
|
rcu_read_unlock();
|
||||||
return err;
|
return err;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -965,7 +963,8 @@ int ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group,
|
||||||
struct ifmcaddr6 *mc;
|
struct ifmcaddr6 *mc;
|
||||||
int rv = 0;
|
int rv = 0;
|
||||||
|
|
||||||
idev = in6_dev_get(dev);
|
rcu_read_lock();
|
||||||
|
idev = __in6_dev_get(dev);
|
||||||
if (idev) {
|
if (idev) {
|
||||||
read_lock_bh(&idev->lock);
|
read_lock_bh(&idev->lock);
|
||||||
for (mc = idev->mc_list; mc; mc=mc->next) {
|
for (mc = idev->mc_list; mc; mc=mc->next) {
|
||||||
|
@ -992,8 +991,8 @@ int ipv6_chk_mcast_addr(struct net_device *dev, const struct in6_addr *group,
|
||||||
rv = 1; /* don't filter unspecified source */
|
rv = 1; /* don't filter unspecified source */
|
||||||
}
|
}
|
||||||
read_unlock_bh(&idev->lock);
|
read_unlock_bh(&idev->lock);
|
||||||
in6_dev_put(idev);
|
|
||||||
}
|
}
|
||||||
|
rcu_read_unlock();
|
||||||
return rv;
|
return rv;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1104,6 +1103,7 @@ static int mld_marksources(struct ifmcaddr6 *pmc, int nsrcs,
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* called with rcu_read_lock() */
|
||||||
int igmp6_event_query(struct sk_buff *skb)
|
int igmp6_event_query(struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct mld2_query *mlh2 = NULL;
|
struct mld2_query *mlh2 = NULL;
|
||||||
|
@ -1127,7 +1127,7 @@ int igmp6_event_query(struct sk_buff *skb)
|
||||||
if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL))
|
if (!(ipv6_addr_type(&ipv6_hdr(skb)->saddr) & IPV6_ADDR_LINKLOCAL))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
idev = in6_dev_get(skb->dev);
|
idev = __in6_dev_get(skb->dev);
|
||||||
|
|
||||||
if (idev == NULL)
|
if (idev == NULL)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1137,10 +1137,8 @@ int igmp6_event_query(struct sk_buff *skb)
|
||||||
group_type = ipv6_addr_type(group);
|
group_type = ipv6_addr_type(group);
|
||||||
|
|
||||||
if (group_type != IPV6_ADDR_ANY &&
|
if (group_type != IPV6_ADDR_ANY &&
|
||||||
!(group_type&IPV6_ADDR_MULTICAST)) {
|
!(group_type&IPV6_ADDR_MULTICAST))
|
||||||
in6_dev_put(idev);
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
|
||||||
|
|
||||||
if (len == 24) {
|
if (len == 24) {
|
||||||
int switchback;
|
int switchback;
|
||||||
|
@ -1161,10 +1159,9 @@ int igmp6_event_query(struct sk_buff *skb)
|
||||||
} else if (len >= 28) {
|
} else if (len >= 28) {
|
||||||
int srcs_offset = sizeof(struct mld2_query) -
|
int srcs_offset = sizeof(struct mld2_query) -
|
||||||
sizeof(struct icmp6hdr);
|
sizeof(struct icmp6hdr);
|
||||||
if (!pskb_may_pull(skb, srcs_offset)) {
|
if (!pskb_may_pull(skb, srcs_offset))
|
||||||
in6_dev_put(idev);
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
|
||||||
mlh2 = (struct mld2_query *)skb_transport_header(skb);
|
mlh2 = (struct mld2_query *)skb_transport_header(skb);
|
||||||
max_delay = (MLDV2_MRC(ntohs(mlh2->mld2q_mrc))*HZ)/1000;
|
max_delay = (MLDV2_MRC(ntohs(mlh2->mld2q_mrc))*HZ)/1000;
|
||||||
if (!max_delay)
|
if (!max_delay)
|
||||||
|
@ -1173,28 +1170,23 @@ int igmp6_event_query(struct sk_buff *skb)
|
||||||
if (mlh2->mld2q_qrv)
|
if (mlh2->mld2q_qrv)
|
||||||
idev->mc_qrv = mlh2->mld2q_qrv;
|
idev->mc_qrv = mlh2->mld2q_qrv;
|
||||||
if (group_type == IPV6_ADDR_ANY) { /* general query */
|
if (group_type == IPV6_ADDR_ANY) { /* general query */
|
||||||
if (mlh2->mld2q_nsrcs) {
|
if (mlh2->mld2q_nsrcs)
|
||||||
in6_dev_put(idev);
|
|
||||||
return -EINVAL; /* no sources allowed */
|
return -EINVAL; /* no sources allowed */
|
||||||
}
|
|
||||||
mld_gq_start_timer(idev);
|
mld_gq_start_timer(idev);
|
||||||
in6_dev_put(idev);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
/* mark sources to include, if group & source-specific */
|
/* mark sources to include, if group & source-specific */
|
||||||
if (mlh2->mld2q_nsrcs != 0) {
|
if (mlh2->mld2q_nsrcs != 0) {
|
||||||
if (!pskb_may_pull(skb, srcs_offset +
|
if (!pskb_may_pull(skb, srcs_offset +
|
||||||
ntohs(mlh2->mld2q_nsrcs) * sizeof(struct in6_addr))) {
|
ntohs(mlh2->mld2q_nsrcs) * sizeof(struct in6_addr)))
|
||||||
in6_dev_put(idev);
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
|
||||||
mlh2 = (struct mld2_query *)skb_transport_header(skb);
|
mlh2 = (struct mld2_query *)skb_transport_header(skb);
|
||||||
mark = 1;
|
mark = 1;
|
||||||
}
|
}
|
||||||
} else {
|
} else
|
||||||
in6_dev_put(idev);
|
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
|
||||||
|
|
||||||
read_lock_bh(&idev->lock);
|
read_lock_bh(&idev->lock);
|
||||||
if (group_type == IPV6_ADDR_ANY) {
|
if (group_type == IPV6_ADDR_ANY) {
|
||||||
|
@ -1227,12 +1219,11 @@ int igmp6_event_query(struct sk_buff *skb)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
read_unlock_bh(&idev->lock);
|
read_unlock_bh(&idev->lock);
|
||||||
in6_dev_put(idev);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* called with rcu_read_lock() */
|
||||||
int igmp6_event_report(struct sk_buff *skb)
|
int igmp6_event_report(struct sk_buff *skb)
|
||||||
{
|
{
|
||||||
struct ifmcaddr6 *ma;
|
struct ifmcaddr6 *ma;
|
||||||
|
@ -1260,7 +1251,7 @@ int igmp6_event_report(struct sk_buff *skb)
|
||||||
!(addr_type&IPV6_ADDR_LINKLOCAL))
|
!(addr_type&IPV6_ADDR_LINKLOCAL))
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
|
|
||||||
idev = in6_dev_get(skb->dev);
|
idev = __in6_dev_get(skb->dev);
|
||||||
if (idev == NULL)
|
if (idev == NULL)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
|
@ -1280,7 +1271,6 @@ int igmp6_event_report(struct sk_buff *skb)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
read_unlock_bh(&idev->lock);
|
read_unlock_bh(&idev->lock);
|
||||||
in6_dev_put(idev);
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1396,12 +1386,14 @@ static void mld_sendpack(struct sk_buff *skb)
|
||||||
struct mld2_report *pmr =
|
struct mld2_report *pmr =
|
||||||
(struct mld2_report *)skb_transport_header(skb);
|
(struct mld2_report *)skb_transport_header(skb);
|
||||||
int payload_len, mldlen;
|
int payload_len, mldlen;
|
||||||
struct inet6_dev *idev = in6_dev_get(skb->dev);
|
struct inet6_dev *idev;
|
||||||
struct net *net = dev_net(skb->dev);
|
struct net *net = dev_net(skb->dev);
|
||||||
int err;
|
int err;
|
||||||
struct flowi fl;
|
struct flowi fl;
|
||||||
struct dst_entry *dst;
|
struct dst_entry *dst;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
idev = __in6_dev_get(skb->dev);
|
||||||
IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);
|
IP6_UPD_PO_STATS(net, idev, IPSTATS_MIB_OUT, skb->len);
|
||||||
|
|
||||||
payload_len = (skb->tail - skb->network_header) - sizeof(*pip6);
|
payload_len = (skb->tail - skb->network_header) - sizeof(*pip6);
|
||||||
|
@ -1441,8 +1433,7 @@ out:
|
||||||
} else
|
} else
|
||||||
IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_OUTDISCARDS);
|
IP6_INC_STATS_BH(net, idev, IPSTATS_MIB_OUTDISCARDS);
|
||||||
|
|
||||||
if (likely(idev != NULL))
|
rcu_read_unlock();
|
||||||
in6_dev_put(idev);
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
err_out:
|
err_out:
|
||||||
|
@ -1779,7 +1770,8 @@ static void igmp6_send(struct in6_addr *addr, struct net_device *dev, int type)
|
||||||
IPPROTO_ICMPV6,
|
IPPROTO_ICMPV6,
|
||||||
csum_partial(hdr, len, 0));
|
csum_partial(hdr, len, 0));
|
||||||
|
|
||||||
idev = in6_dev_get(skb->dev);
|
rcu_read_lock();
|
||||||
|
idev = __in6_dev_get(skb->dev);
|
||||||
|
|
||||||
dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr);
|
dst = icmp6_dst_alloc(skb->dev, NULL, &ipv6_hdr(skb)->daddr);
|
||||||
if (!dst) {
|
if (!dst) {
|
||||||
|
@ -1806,8 +1798,7 @@ out:
|
||||||
} else
|
} else
|
||||||
IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTDISCARDS);
|
IP6_INC_STATS(net, idev, IPSTATS_MIB_OUTDISCARDS);
|
||||||
|
|
||||||
if (likely(idev != NULL))
|
rcu_read_unlock();
|
||||||
in6_dev_put(idev);
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
err_out:
|
err_out:
|
||||||
|
|
Loading…
Add table
Reference in a new issue