include cleanup: Update gfp.h and slab.h includes to prepare for breaking implicit...
[safe/jmp/linux-2.6] / net / ipv4 / ipmr.c
index c43ec2d..9d4f6d1 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/mroute.h>
 #include <linux/init.h>
 #include <linux/if_ether.h>
+#include <linux/slab.h>
 #include <net/net_namespace.h>
 #include <net/ip.h>
 #include <net/protocol.h>
@@ -275,7 +276,8 @@ failure:
  *     @notify: Set to 1, if the caller is a notifier_call
  */
 
-static int vif_delete(struct net *net, int vifi, int notify)
+static int vif_delete(struct net *net, int vifi, int notify,
+                     struct list_head *head)
 {
        struct vif_device *v;
        struct net_device *dev;
@@ -319,7 +321,7 @@ static int vif_delete(struct net *net, int vifi, int notify)
        }
 
        if (v->flags&(VIFF_TUNNEL|VIFF_REGISTER) && !notify)
-               unregister_netdevice(dev);
+               unregister_netdevice_queue(dev, head);
 
        dev_put(dev);
        return 0;
@@ -469,8 +471,18 @@ static int vif_add(struct net *net, struct vifctl *vifc, int mrtsock)
                        return err;
                }
                break;
+
+       case VIFF_USE_IFINDEX:
        case 0:
-               dev = ip_dev_find(net, vifc->vifc_lcl_addr.s_addr);
+               if (vifc->vifc_flags == VIFF_USE_IFINDEX) {
+                       dev = dev_get_by_index(net, vifc->vifc_lcl_ifindex);
+                       if (dev && dev->ip_ptr == NULL) {
+                               dev_put(dev);
+                               return -EADDRNOTAVAIL;
+                       }
+               } else
+                       dev = ip_dev_find(net, vifc->vifc_lcl_addr.s_addr);
+
                if (!dev)
                        return -EADDRNOTAVAIL;
                err = dev_set_allmulti(dev, 1);
@@ -483,8 +495,10 @@ static int vif_add(struct net *net, struct vifctl *vifc, int mrtsock)
                return -EINVAL;
        }
 
-       if ((in_dev = __in_dev_get_rtnl(dev)) == NULL)
+       if ((in_dev = __in_dev_get_rtnl(dev)) == NULL) {
+               dev_put(dev);
                return -EADDRNOTAVAIL;
+       }
        IPV4_DEVCONF(in_dev->cnf, MC_FORWARDING)++;
        ip_rt_multicast_event(in_dev);
 
@@ -789,6 +803,9 @@ static int ipmr_mfc_add(struct net *net, struct mfcctl *mfc, int mrtsock)
        int line;
        struct mfc_cache *uc, *c, **cp;
 
+       if (mfc->mfcc_parent >= MAXVIFS)
+               return -ENFILE;
+
        line = MFC_HASH(mfc->mfcc_mcastgrp.s_addr, mfc->mfcc_origin.s_addr);
 
        for (cp = &net->ipv4.mfc_cache_array[line];
@@ -860,14 +877,16 @@ static int ipmr_mfc_add(struct net *net, struct mfcctl *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->ipv4.maxvif; i++) {
                if (!(net->ipv4.vif_table[i].flags&VIFF_STATIC))
-                       vif_delete(net, i, 0);
+                       vif_delete(net, i, 0, &list);
        }
+       unregister_netdevice_many(&list);
 
        /*
         *      Wipe the cache
@@ -931,7 +950,7 @@ static void mrtsock_destruct(struct sock *sk)
  *     MOSPF/PIM router set up we can clean this up.
  */
 
-int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int optlen)
+int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, unsigned int optlen)
 {
        int ret;
        struct vifctl vif;
@@ -946,7 +965,7 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int
        switch (optname) {
        case MRT_INIT:
                if (sk->sk_type != SOCK_RAW ||
-                   inet_sk(sk)->num != IPPROTO_IGMP)
+                   inet_sk(sk)->inet_num != IPPROTO_IGMP)
                        return -EOPNOTSUPP;
                if (optlen != sizeof(int))
                        return -ENOPROTOOPT;
@@ -983,7 +1002,7 @@ int ip_mroute_setsockopt(struct sock *sk, int optname, char __user *optval, int
                if (optname == MRT_ADD_VIF) {
                        ret = vif_add(net, &vif, sk == net->ipv4.mroute_sk);
                } else {
-                       ret = vif_delete(net, vif.vifc_vifi, 0);
+                       ret = vif_delete(net, vif.vifc_vifi, 0, NULL);
                }
                rtnl_unlock();
                return ret;
@@ -1146,17 +1165,16 @@ static int ipmr_device_event(struct notifier_block *this, unsigned long event, v
        struct net *net = dev_net(dev);
        struct vif_device *v;
        int ct;
-
-       if (!net_eq(dev_net(dev), net))
-               return NOTIFY_DONE;
+       LIST_HEAD(list);
 
        if (event != NETDEV_UNREGISTER)
                return NOTIFY_DONE;
        v = &net->ipv4.vif_table[0];
        for (ct = 0; ct < net->ipv4.maxvif; ct++, v++) {
                if (v->dev == dev)
-                       vif_delete(net, ct, 1);
+                       vif_delete(net, ct, 1, &list);
        }
+       unregister_netdevice_many(&list);
        return NOTIFY_DONE;
 }
 
@@ -1599,17 +1617,20 @@ ipmr_fill_mroute(struct sk_buff *skb, struct mfc_cache *c, struct rtmsg *rtm)
        int ct;
        struct rtnexthop *nhp;
        struct net *net = mfc_net(c);
-       struct net_device *dev = net->ipv4.vif_table[c->mfc_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->mfc_parent > MAXVIFS)
+               return -ENOENT;
+
+       if (VIF_EXISTS(net, c->mfc_parent))
+               RTA_PUT(skb, RTA_IIF, 4, &net->ipv4.vif_table[c->mfc_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 (VIF_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)));