ipv6,mcast: always hold idev->lock before mca_lock
[pandora-kernel.git] / net / ipv6 / mcast.c
index ee7839f..c7ec4bb 100644 (file)
@@ -257,7 +257,6 @@ static struct inet6_dev *ip6_mc_find_dev_rcu(struct net *net,
 
                if (rt) {
                        dev = rt->rt6i_dev;
-                       dev_hold(dev);
                        dst_release(&rt->dst);
                }
        } else
@@ -1335,8 +1334,9 @@ mld_scount(struct ifmcaddr6 *pmc, int type, int gdeleted, int sdeleted)
        return scount;
 }
 
-static struct sk_buff *mld_newpack(struct net_device *dev, int size)
+static struct sk_buff *mld_newpack(struct inet6_dev *idev, int size)
 {
+       struct net_device *dev = idev->dev;
        struct net *net = dev_net(dev);
        struct sock *sk = net->ipv6.igmp_sk;
        struct sk_buff *skb;
@@ -1359,7 +1359,7 @@ static struct sk_buff *mld_newpack(struct net_device *dev, int size)
 
        skb_reserve(skb, LL_RESERVED_SPACE(dev));
 
-       if (ipv6_get_lladdr(dev, &addr_buf, IFA_F_TENTATIVE)) {
+       if (__ipv6_get_lladdr(idev, &addr_buf, IFA_F_TENTATIVE)) {
                /* <draft-ietf-magma-mld-source-05.txt>:
                 * use unspecified address as the source address
                 * when a valid link-local address is not available.
@@ -1462,7 +1462,7 @@ static struct sk_buff *add_grhead(struct sk_buff *skb, struct ifmcaddr6 *pmc,
        struct mld2_grec *pgr;
 
        if (!skb)
-               skb = mld_newpack(dev, dev->mtu);
+               skb = mld_newpack(pmc->idev, dev->mtu);
        if (!skb)
                return NULL;
        pgr = (struct mld2_grec *)skb_put(skb, sizeof(struct mld2_grec));
@@ -1482,7 +1482,8 @@ static struct sk_buff *add_grhead(struct sk_buff *skb, struct ifmcaddr6 *pmc,
 static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc,
        int type, int gdeleted, int sdeleted)
 {
-       struct net_device *dev = pmc->idev->dev;
+       struct inet6_dev *idev = pmc->idev;
+       struct net_device *dev = idev->dev;
        struct mld2_report *pmr;
        struct mld2_grec *pgr = NULL;
        struct ip6_sf_list *psf, *psf_next, *psf_prev, **psf_list;
@@ -1511,7 +1512,7 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc,
                    AVAILABLE(skb) < grec_size(pmc, type, gdeleted, sdeleted)) {
                        if (skb)
                                mld_sendpack(skb);
-                       skb = mld_newpack(dev, dev->mtu);
+                       skb = mld_newpack(idev, dev->mtu);
                }
        }
        first = 1;
@@ -1538,7 +1539,7 @@ static struct sk_buff *add_grec(struct sk_buff *skb, struct ifmcaddr6 *pmc,
                                pgr->grec_nsrcs = htons(scount);
                        if (skb)
                                mld_sendpack(skb);
-                       skb = mld_newpack(dev, dev->mtu);
+                       skb = mld_newpack(idev, dev->mtu);
                        first = 1;
                        scount = 0;
                }
@@ -1593,8 +1594,8 @@ static void mld_send_report(struct inet6_dev *idev, struct ifmcaddr6 *pmc)
        struct sk_buff *skb = NULL;
        int type;
 
+       read_lock_bh(&idev->lock);
        if (!pmc) {
-               read_lock_bh(&idev->lock);
                for (pmc=idev->mc_list; pmc; pmc=pmc->next) {
                        if (pmc->mca_flags & MAF_NOREPORT)
                                continue;
@@ -1606,7 +1607,6 @@ static void mld_send_report(struct inet6_dev *idev, struct ifmcaddr6 *pmc)
                        skb = add_grec(skb, pmc, type, 0, 0);
                        spin_unlock_bh(&pmc->mca_lock);
                }
-               read_unlock_bh(&idev->lock);
        } else {
                spin_lock_bh(&pmc->mca_lock);
                if (pmc->mca_sfcount[MCAST_EXCLUDE])
@@ -1616,6 +1616,7 @@ static void mld_send_report(struct inet6_dev *idev, struct ifmcaddr6 *pmc)
                skb = add_grec(skb, pmc, type, 0, 0);
                spin_unlock_bh(&pmc->mca_lock);
        }
+       read_unlock_bh(&idev->lock);
        if (skb)
                mld_sendpack(skb);
 }
@@ -2055,7 +2056,7 @@ static int ip6_mc_add_src(struct inet6_dev *idev, const struct in6_addr *pmca,
                if (!delta)
                        pmc->mca_sfcount[sfmode]--;
                for (j=0; j<i; j++)
-                       (void) ip6_mc_del1_src(pmc, sfmode, &psfsrc[i]);
+                       ip6_mc_del1_src(pmc, sfmode, &psfsrc[j]);
        } else if (isexclude != (pmc->mca_sfcount[MCAST_EXCLUDE] != 0)) {
                struct ip6_sf_list *psf;