Merge branch 'master' of git://dev.medozas.de/linux
[safe/jmp/linux-2.6] / net / ipv6 / ip6mr.c
index 5c8d737..e0b530c 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <linux/init.h>
+#include <linux/slab.h>
 #include <net/protocol.h>
 #include <linux/skbuff.h>
 #include <net/sock.h>
@@ -83,10 +84,6 @@ static int ip6mr_cache_report(struct net *net, struct sk_buff *pkt,
 static int ip6mr_fill_mroute(struct sk_buff *skb, struct mfc6_cache *c, struct rtmsg *rtm);
 static void mroute_clean_tables(struct net *net);
 
-#ifdef CONFIG_IPV6_PIMSM_V2
-static struct inet6_protocol pim6_protocol;
-#endif
-
 static struct timer_list ipmr_expire_timer;
 
 
@@ -328,7 +325,7 @@ static int ipmr_mfc_seq_show(struct seq_file *seq, void *v)
        return 0;
 }
 
-static struct seq_operations ipmr_mfc_seq_ops = {
+static const struct seq_operations ipmr_mfc_seq_ops = {
        .start = ipmr_mfc_seq_start,
        .next  = ipmr_mfc_seq_next,
        .stop  = ipmr_mfc_seq_stop,
@@ -410,7 +407,7 @@ static int pim6_rcv(struct sk_buff *skb)
        return 0;
 }
 
-static struct inet6_protocol pim6_protocol = {
+static const struct inet6_protocol pim6_protocol = {
        .handler        =       pim6_rcv,
 };
 
@@ -481,7 +478,7 @@ failure:
  *     Delete a VIF entry
  */
 
-static int mif6_delete(struct net *net, int vifi)
+static int mif6_delete(struct net *net, int vifi, struct list_head *head)
 {
        struct mif_device *v;
        struct net_device *dev;
@@ -523,7 +520,7 @@ static int mif6_delete(struct net *net, int vifi)
                in6_dev->cnf.mc_forwarding--;
 
        if (v->flags & MIFF_REGISTER)
-               unregister_netdevice(dev);
+               unregister_netdevice_queue(dev, head);
 
        dev_put(dev);
        return 0;
@@ -980,6 +977,7 @@ static int ip6mr_device_event(struct notifier_block *this,
        struct net *net = dev_net(dev);
        struct mif_device *v;
        int ct;
+       LIST_HEAD(list);
 
        if (event != NETDEV_UNREGISTER)
                return NOTIFY_DONE;
@@ -987,8 +985,10 @@ static int ip6mr_device_event(struct notifier_block *this,
        v = &net->ipv6.vif6_table[0];
        for (ct = 0; ct < net->ipv6.maxvif; ct++, v++) {
                if (v->dev == dev)
-                       mif6_delete(net, ct);
+                       mif6_delete(net, ct, &list);
        }
+       unregister_netdevice_many(&list);
+
        return NOTIFY_DONE;
 }
 
@@ -1114,6 +1114,9 @@ static int ip6mr_mfc_add(struct net *net, struct mf6cctl *mfc, int mrtsock)
        unsigned char ttls[MAXMIFS];
        int i;
 
+       if (mfc->mf6cc_parent >= MAXMIFS)
+               return -ENFILE;
+
        memset(ttls, 255, MAXMIFS);
        for (i = 0; i < MAXMIFS; i++) {
                if (IF_ISSET(i, &mfc->mf6cc_ifset))
@@ -1192,14 +1195,16 @@ static int ip6mr_mfc_add(struct net *net, struct mf6cctl *mfc, int mrtsock)
 static void mroute_clean_tables(struct net *net)
 {
        int i;
+       LIST_HEAD(list);
 
        /*
         *      Shut down all active vif entries
         */
        for (i = 0; i < net->ipv6.maxvif; i++) {
                if (!(net->ipv6.vif6_table[i].flags & VIFF_STATIC))
-                       mif6_delete(net, i);
+                       mif6_delete(net, i, &list);
        }
+       unregister_netdevice_many(&list);
 
        /*
         *      Wipe the cache
@@ -1285,7 +1290,7 @@ int ip6mr_sk_done(struct sock *sk)
  *     MOSPF/PIM router set up we can clean this up.
  */
 
-int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int optlen)
+int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen)
 {
        int ret;
        struct mif6ctl vif;
@@ -1301,7 +1306,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int
        switch (optname) {
        case MRT6_INIT:
                if (sk->sk_type != SOCK_RAW ||
-                   inet_sk(sk)->num != IPPROTO_ICMPV6)
+                   inet_sk(sk)->inet_num != IPPROTO_ICMPV6)
                        return -EOPNOTSUPP;
                if (optlen < sizeof(int))
                        return -EINVAL;
@@ -1329,7 +1334,7 @@ int ip6_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int
                if (copy_from_user(&mifi, optval, sizeof(mifi_t)))
                        return -EFAULT;
                rtnl_lock();
-               ret = mif6_delete(net, mifi);
+               ret = mif6_delete(net, mifi, NULL);
                rtnl_unlock();
                return ret;
 
@@ -1565,7 +1570,7 @@ static int ip6mr_forward2(struct sk_buff *skb, struct mfc6_cache *c, int vifi)
 
        IP6CB(skb)->flags |= IP6SKB_FORWARDED;
 
-       return NF_HOOK(PF_INET6, NF_INET_FORWARD, skb, skb->dev, dev,
+       return NF_HOOK(NFPROTO_IPV6, NF_INET_FORWARD, skb, skb->dev, dev,
                       ip6mr_forward2_finish);
 
 out_free:
@@ -1691,17 +1696,20 @@ ip6mr_fill_mroute(struct sk_buff *skb, struct mfc6_cache *c, struct rtmsg *rtm)
        int ct;
        struct rtnexthop *nhp;
        struct net *net = mfc6_net(c);
-       struct net_device *dev = net->ipv6.vif6_table[c->mf6c_parent].dev;
        u8 *b = skb_tail_pointer(skb);
        struct rtattr *mp_head;
 
-       if (dev)
-               RTA_PUT(skb, RTA_IIF, 4, &dev->ifindex);
+       /* If cache is unresolved, don't try to parse IIF and OIF */
+       if (c->mf6c_parent > MAXMIFS)
+               return -ENOENT;
+
+       if (MIF_EXISTS(net, c->mf6c_parent))
+               RTA_PUT(skb, RTA_IIF, 4, &net->ipv6.vif6_table[c->mf6c_parent].dev->ifindex);
 
        mp_head = (struct rtattr *)skb_put(skb, RTA_LENGTH(0));
 
        for (ct = c->mfc_un.res.minvif; ct < c->mfc_un.res.maxvif; ct++) {
-               if (c->mfc_un.res.ttls[ct] < 255) {
+               if (MIF_EXISTS(net, ct) && c->mfc_un.res.ttls[ct] < 255) {
                        if (skb_tailroom(skb) < RTA_ALIGN(RTA_ALIGN(sizeof(*nhp)) + 4))
                                goto rtattr_failure;
                        nhp = (struct rtnexthop *)skb_put(skb, RTA_ALIGN(sizeof(*nhp)));