]> git.karo-electronics.de Git - karo-tx-linux.git/blobdiff - net/ipv6/ip6mr.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/dtor/input
[karo-tx-linux.git] / net / ipv6 / ip6mr.c
index 3c51b2d827f4b82966502e7a210c028260f52419..228be551e9c1d896eb97ba00ec78fc80cc47d2c0 100644 (file)
@@ -48,6 +48,7 @@
 #include <linux/pim.h>
 #include <net/addrconf.h>
 #include <linux/netfilter_ipv6.h>
+#include <net/ip6_checksum.h>
 
 /* Big lock, protecting vif table, mrt cache and mroute socket state.
    Note that the changes are semaphored via rtnl_lock.
@@ -365,7 +366,9 @@ static int pim6_rcv(struct sk_buff *skb)
        pim = (struct pimreghdr *)skb_transport_header(skb);
        if (pim->type != ((PIM_VERSION << 4) | PIM_REGISTER) ||
            (pim->flags & PIM_NULL_REGISTER) ||
-           (ip_compute_csum((void *)pim, sizeof(*pim)) != 0 &&
+           (csum_ipv6_magic(&ipv6_hdr(skb)->saddr, &ipv6_hdr(skb)->daddr,
+                            sizeof(*pim), IPPROTO_PIM,
+                            csum_partial((void *)pim, sizeof(*pim), 0)) &&
             csum_fold(skb_checksum(skb, 0, skb->len, 0))))
                goto drop;
 
@@ -392,7 +395,7 @@ static int pim6_rcv(struct sk_buff *skb)
        skb_pull(skb, (u8 *)encap - skb->data);
        skb_reset_network_header(skb);
        skb->dev = reg_dev;
-       skb->protocol = htons(ETH_P_IP);
+       skb->protocol = htons(ETH_P_IPV6);
        skb->ip_summed = 0;
        skb->pkt_type = PACKET_HOST;
        dst_release(skb->dst);
@@ -481,6 +484,7 @@ static int mif6_delete(struct net *net, int vifi)
 {
        struct mif_device *v;
        struct net_device *dev;
+       struct inet6_dev *in6_dev;
        if (vifi < 0 || vifi >= net->ipv6.maxvif)
                return -EADDRNOTAVAIL;
 
@@ -513,6 +517,10 @@ static int mif6_delete(struct net *net, int vifi)
 
        dev_set_allmulti(dev, -1);
 
+       in6_dev = __in6_dev_get(dev);
+       if (in6_dev)
+               in6_dev->cnf.mc_forwarding--;
+
        if (v->flags & MIFF_REGISTER)
                unregister_netdevice(dev);
 
@@ -622,6 +630,7 @@ static int mif6_add(struct net *net, struct mif6ctl *vifc, int mrtsock)
        int vifi = vifc->mif6c_mifi;
        struct mif_device *v = &net->ipv6.vif6_table[vifi];
        struct net_device *dev;
+       struct inet6_dev *in6_dev;
        int err;
 
        /* Is vif busy ? */
@@ -662,6 +671,10 @@ static int mif6_add(struct net *net, struct mif6ctl *vifc, int mrtsock)
                return -EINVAL;
        }
 
+       in6_dev = __in6_dev_get(dev);
+       if (in6_dev)
+               in6_dev->cnf.mc_forwarding++;
+
        /*
         *      Fill in the VIF structures
         */
@@ -838,8 +851,6 @@ static int ip6mr_cache_report(struct net *net, struct sk_buff *pkt, mifi_t mifi,
 
        skb->dst = dst_clone(pkt->dst);
        skb->ip_summed = CHECKSUM_UNNECESSARY;
-
-       skb_pull(skb, sizeof(struct ipv6hdr));
        }
 
        if (net->ipv6.mroute6_sk == NULL) {
@@ -1222,8 +1233,10 @@ static int ip6mr_sk_init(struct sock *sk)
 
        rtnl_lock();
        write_lock_bh(&mrt_lock);
-       if (likely(net->ipv6.mroute6_sk == NULL))
+       if (likely(net->ipv6.mroute6_sk == NULL)) {
                net->ipv6.mroute6_sk = sk;
+               net->ipv6.devconf_all->mc_forwarding++;
+       }
        else
                err = -EADDRINUSE;
        write_unlock_bh(&mrt_lock);
@@ -1242,6 +1255,7 @@ int ip6mr_sk_done(struct sock *sk)
        if (sk == net->ipv6.mroute6_sk) {
                write_lock_bh(&mrt_lock);
                net->ipv6.mroute6_sk = NULL;
+               net->ipv6.devconf_all->mc_forwarding--;
                write_unlock_bh(&mrt_lock);
 
                mroute_clean_tables(net);