linux 2.6.16.38 w/ vs2.0.3-rc1
[linux-2.6.git] / net / decnet / dn_dev.c
index bc27c4e..efbead8 100644 (file)
@@ -25,6 +25,7 @@
  */
 
 #include <linux/config.h>
+#include <linux/capability.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
@@ -41,6 +42,7 @@
 #include <linux/sysctl.h>
 #include <linux/notifier.h>
 #include <asm/uaccess.h>
+#include <asm/system.h>
 #include <net/neighbour.h>
 #include <net/dst.h>
 #include <net/flow.h>
@@ -64,7 +66,7 @@ extern struct neigh_table dn_neigh_table;
  */
 dn_address decnet_address = 0;
 
-static rwlock_t dndev_lock = RW_LOCK_UNLOCKED;
+static DEFINE_RWLOCK(dndev_lock);
 static struct net_device *decnet_default_device;
 static struct notifier_block *dnaddr_chain;
 
@@ -161,10 +163,10 @@ static int min_priority[1];
 static int max_priority[] = { 127 }; /* From DECnet spec */
 
 static int dn_forwarding_proc(ctl_table *, int, struct file *,
-                       void *, size_t *);
-static int dn_forwarding_sysctl(ctl_table *table, int *name, int nlen,
-                       void *oldval, size_t *oldlenp,
-                       void *newval, size_t newlen,
+                       void __user *, size_t *, loff_t *);
+static int dn_forwarding_sysctl(ctl_table *table, int __user *name, int nlen,
+                       void __user *oldval, size_t __user *oldlenp,
+                       void __user *newval, size_t newlen,
                        void **context);
 
 static struct dn_dev_sysctl_table {
@@ -247,21 +249,6 @@ static struct dn_dev_sysctl_table {
        }, {0}}
 };
 
-static inline __u16 mtu2blksize(struct net_device *dev)
-{
-       u32 blksize = dev->mtu;
-       if (blksize > 0xffff)
-               blksize = 0xffff;
-
-       if (dev->type == ARPHRD_ETHER ||
-           dev->type == ARPHRD_PPP ||
-           dev->type == ARPHRD_IPGRE ||
-           dev->type == ARPHRD_LOOPBACK)
-               blksize -= 2;
-
-       return (__u16)blksize;
-}
-
 static void dn_dev_sysctl_register(struct net_device *dev, struct dn_dev_parms *parms)
 {
        struct dn_dev_sysctl_table *t;
@@ -314,55 +301,10 @@ static void dn_dev_sysctl_unregister(struct dn_dev_parms *parms)
        }
 }
 
-struct net_device *dn_dev_get_default(void)
-{
-       struct net_device *dev;
-       read_lock(&dndev_lock);
-       dev = decnet_default_device;
-       if (dev) {
-               if (dev->dn_ptr)
-                       dev_hold(dev);
-               else
-                       dev = NULL;
-       }
-       read_unlock(&dndev_lock);
-       return dev;
-}
-
-int dn_dev_set_default(struct net_device *dev, int force)
-{
-       struct net_device *old = NULL;
-       int rv = -EBUSY;
-       if (!dev->dn_ptr)
-               return -ENODEV;
-       write_lock(&dndev_lock);
-       if (force || decnet_default_device == NULL) {
-               old = decnet_default_device;
-               decnet_default_device = dev;
-               rv = 0;
-       }
-       write_unlock(&dndev_lock);
-       if (old)
-               dev_put(dev);
-       return rv;
-}
-
-static void dn_dev_check_default(struct net_device *dev)
-{
-       write_lock(&dndev_lock);
-       if (dev == decnet_default_device) {
-               decnet_default_device = NULL;
-       } else {
-               dev = NULL;
-       }
-       write_unlock(&dndev_lock);
-       if (dev)
-               dev_put(dev);
-}
-
 static int dn_forwarding_proc(ctl_table *table, int write, 
                                struct file *filep,
-                               void *buffer, size_t *lenp)
+                               void __user *buffer,
+                               size_t *lenp, loff_t *ppos)
 {
 #ifdef CONFIG_DECNET_ROUTER
        struct net_device *dev = table->extra1;
@@ -376,7 +318,7 @@ static int dn_forwarding_proc(ctl_table *table, int write,
        dn_db = dev->dn_ptr;
        old = dn_db->parms.forwarding;
 
-       err = proc_dointvec(table, write, filep, buffer, lenp);
+       err = proc_dointvec(table, write, filep, buffer, lenp, ppos);
 
        if ((err >= 0) && write) {
                if (dn_db->parms.forwarding < 0)
@@ -404,9 +346,9 @@ static int dn_forwarding_proc(ctl_table *table, int write,
 #endif
 }
 
-static int dn_forwarding_sysctl(ctl_table *table, int *name, int nlen,
-                       void *oldval, size_t *oldlenp,
-                       void *newval, size_t newlen,
+static int dn_forwarding_sysctl(ctl_table *table, int __user *name, int nlen,
+                       void __user *oldval, size_t __user *oldlenp,
+                       void __user *newval, size_t newlen,
                        void **context)
 {
 #ifdef CONFIG_DECNET_ROUTER
@@ -423,7 +365,7 @@ static int dn_forwarding_sysctl(ctl_table *table, int *name, int nlen,
                if (newlen != sizeof(int))
                        return -EINVAL;
 
-               if (get_user(value, (int *)newval))
+               if (get_user(value, (int __user *)newval))
                        return -EFAULT;
                if (value < 0)
                        return -EINVAL;
@@ -453,6 +395,21 @@ static void dn_dev_sysctl_register(struct net_device *dev, struct dn_dev_parms *
 
 #endif /* CONFIG_SYSCTL */
 
+static inline __u16 mtu2blksize(struct net_device *dev)
+{
+       u32 blksize = dev->mtu;
+       if (blksize > 0xffff)
+               blksize = 0xffff;
+
+       if (dev->type == ARPHRD_ETHER ||
+           dev->type == ARPHRD_PPP ||
+           dev->type == ARPHRD_IPGRE ||
+           dev->type == ARPHRD_LOOPBACK)
+               blksize -= 2;
+
+       return (__u16)blksize;
+}
+
 static struct dn_ifaddr *dn_dev_alloc_ifa(void)
 {
        struct dn_ifaddr *ifa;
@@ -553,7 +510,7 @@ static int dn_dev_set_ifa(struct net_device *dev, struct dn_ifaddr *ifa)
 }
 
 
-int dn_dev_ioctl(unsigned int cmd, void *arg)
+int dn_dev_ioctl(unsigned int cmd, void __user *arg)
 {
        char buffer[DN_IFREQ_SIZE];
        struct ifreq *ifr = (struct ifreq *)buffer;
@@ -634,6 +591,52 @@ rarok:
        goto done;
 }
 
+struct net_device *dn_dev_get_default(void)
+{
+       struct net_device *dev;
+       read_lock(&dndev_lock);
+       dev = decnet_default_device;
+       if (dev) {
+               if (dev->dn_ptr)
+                       dev_hold(dev);
+               else
+                       dev = NULL;
+       }
+       read_unlock(&dndev_lock);
+       return dev;
+}
+
+int dn_dev_set_default(struct net_device *dev, int force)
+{
+       struct net_device *old = NULL;
+       int rv = -EBUSY;
+       if (!dev->dn_ptr)
+               return -ENODEV;
+       write_lock(&dndev_lock);
+       if (force || decnet_default_device == NULL) {
+               old = decnet_default_device;
+               decnet_default_device = dev;
+               rv = 0;
+       }
+       write_unlock(&dndev_lock);
+       if (old)
+               dev_put(dev);
+       return rv;
+}
+
+static void dn_dev_check_default(struct net_device *dev)
+{
+       write_lock(&dndev_lock);
+       if (dev == decnet_default_device) {
+               decnet_default_device = NULL;
+       } else {
+               dev = NULL;
+       }
+       write_unlock(&dndev_lock);
+       if (dev)
+               dev_put(dev);
+}
+
 static struct dn_dev *dn_dev_by_index(int ifindex)
 {
        struct net_device *dev;
@@ -660,7 +663,7 @@ static int dn_dev_rtm_deladdr(struct sk_buff *skb, struct nlmsghdr *nlh, void *a
        for(ifap = &dn_db->ifa_list; (ifa=*ifap) != NULL; ifap = &ifa->ifa_next) {
                void *tmp = rta[IFA_LOCAL-1];
                if ((tmp && memcmp(RTA_DATA(tmp), &ifa->ifa_local, 2)) ||
-                               (rta[IFA_LABEL-1] && strcmp(RTA_DATA(rta[IFA_LABEL-1]), ifa->ifa_label)))
+                   (rta[IFA_LABEL-1] && rtattr_strcmp(rta[IFA_LABEL-1], ifa->ifa_label)))
                        continue;
 
                dn_dev_del_ifa(dn_db, ifap, 1);
@@ -703,7 +706,7 @@ static int dn_dev_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *a
        ifa->ifa_scope = ifm->ifa_scope;
        ifa->ifa_dev = dn_db;
        if (rta[IFA_LABEL-1])
-               memcpy(ifa->ifa_label, RTA_DATA(rta[IFA_LABEL-1]), IFNAMSIZ);
+               rtattr_strlcpy(ifa->ifa_label, rta[IFA_LABEL-1], IFNAMSIZ);
        else
                memcpy(ifa->ifa_label, dev->name, IFNAMSIZ);
 
@@ -714,13 +717,13 @@ static int dn_dev_rtm_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *a
 }
 
 static int dn_dev_fill_ifaddr(struct sk_buff *skb, struct dn_ifaddr *ifa,
-                               u32 pid, u32 seq, int event)
+                               u32 pid, u32 seq, int event, unsigned int flags)
 {
        struct ifaddrmsg *ifm;
        struct nlmsghdr *nlh;
        unsigned char *b = skb->tail;
 
-       nlh = NLMSG_PUT(skb, pid, seq, event, sizeof(*ifm));
+       nlh = NLMSG_NEW(skb, pid, seq, event, sizeof(*ifm), flags);
        ifm = NLMSG_DATA(nlh);
 
        ifm->ifa_family = AF_DECnet;
@@ -750,16 +753,16 @@ static void rtmsg_ifa(int event, struct dn_ifaddr *ifa)
 
        skb = alloc_skb(size, GFP_KERNEL);
        if (!skb) {
-               netlink_set_err(rtnl, 0, RTMGRP_DECnet_IFADDR, ENOBUFS);
+               netlink_set_err(rtnl, 0, RTNLGRP_DECnet_IFADDR, ENOBUFS);
                return;
        }
-       if (dn_dev_fill_ifaddr(skb, ifa, 0, 0, event) < 0) {
+       if (dn_dev_fill_ifaddr(skb, ifa, 0, 0, event, 0) < 0) {
                kfree_skb(skb);
-               netlink_set_err(rtnl, 0, RTMGRP_DECnet_IFADDR, EINVAL);
+               netlink_set_err(rtnl, 0, RTNLGRP_DECnet_IFADDR, EINVAL);
                return;
        }
-       NETLINK_CB(skb).dst_groups = RTMGRP_DECnet_IFADDR;
-       netlink_broadcast(rtnl, skb, 0, RTMGRP_DECnet_IFADDR, GFP_KERNEL);
+       NETLINK_CB(skb).dst_group = RTNLGRP_DECnet_IFADDR;
+       netlink_broadcast(rtnl, skb, 0, RTNLGRP_DECnet_IFADDR, GFP_KERNEL);
 }
 
 static int dn_dev_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
@@ -788,7 +791,8 @@ static int dn_dev_dump_ifaddr(struct sk_buff *skb, struct netlink_callback *cb)
                        if (dn_dev_fill_ifaddr(skb, ifa,
                                               NETLINK_CB(cb->skb).pid,
                                               cb->nlh->nlmsg_seq,
-                                              RTM_NEWADDR) <= 0)
+                                              RTM_NEWADDR,
+                                              NLM_F_MULTI) <= 0)
                                goto done;
                }
        }
@@ -1107,6 +1111,7 @@ struct dn_dev *dn_dev_create(struct net_device *dev, int *err)
 
        memset(dn_db, 0, sizeof(struct dn_dev));
        memcpy(&dn_db->parms, p, sizeof(struct dn_dev_parms));
+       smp_wmb();
        dev->dn_ptr = dn_db;
        dn_db->dev = dev;
        init_timer(&dn_db->timer);
@@ -1214,6 +1219,7 @@ static void dn_dev_delete(struct net_device *dev)
        dev->dn_ptr = NULL;
 
        neigh_parms_release(&dn_neigh_table, dn_db->neigh_parms);
+       neigh_ifdown(&dn_neigh_table, dev);
 
        if (dn_db->router)
                neigh_release(dn_db->router);
@@ -1287,51 +1293,6 @@ int unregister_dnaddr_notifier(struct notifier_block *nb)
        return notifier_chain_unregister(&dnaddr_chain, nb);
 }
 
-#ifdef CONFIG_DECNET_SIOCGIFCONF
-/*
- * Now we support multiple addresses per interface.
- * Since we don't want to break existing code, you have to enable
- * it as a compile time option. Probably you should use the
- * rtnetlink interface instead.
- */
-int dnet_gifconf(struct net_device *dev, char *buf, int len)
-{
-       struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr;
-       struct dn_ifaddr *ifa;
-       struct ifreq *ifr = (struct ifreq *)buf;
-       int done = 0;
-
-       if ((dn_db == NULL) || ((ifa = dn_db->ifa_list) == NULL))
-               return 0;
-
-       for(; ifa; ifa = ifa->ifa_next) {
-               if (!ifr) {
-                       done += sizeof(DN_IFREQ_SIZE);
-                       continue;
-               }
-               if (len < DN_IFREQ_SIZE)
-                       return done;
-               memset(ifr, 0, DN_IFREQ_SIZE);
-
-               if (ifa->ifa_label)
-                       strcpy(ifr->ifr_name, ifa->ifa_label);
-               else
-                       strcpy(ifr->ifr_name, dev->name);
-
-               (*(struct sockaddr_dn *) &ifr->ifr_addr).sdn_family = AF_DECnet;
-               (*(struct sockaddr_dn *) &ifr->ifr_addr).sdn_add.a_len = 2;
-               (*(dn_address *)(*(struct sockaddr_dn *) &ifr->ifr_addr).sdn_add.a_addr) = ifa->ifa_local;
-
-               ifr = (struct ifreq *)((char *)ifr + DN_IFREQ_SIZE);
-               len  -= DN_IFREQ_SIZE;
-               done += DN_IFREQ_SIZE;
-       }
-
-       return done;
-}
-#endif /* CONFIG_DECNET_SIOCGIFCONF */
-
-
 #ifdef CONFIG_PROC_FS
 static inline struct net_device *dn_dev_get_next(struct seq_file *seq, struct net_device *dev)
 {
@@ -1452,28 +1413,28 @@ static struct file_operations dn_dev_seq_fops = {
 
 #endif /* CONFIG_PROC_FS */
 
-static struct rtnetlink_link dnet_rtnetlink_table[RTM_MAX-RTM_BASE+1] = 
+static struct rtnetlink_link dnet_rtnetlink_table[RTM_NR_MSGTYPES] =
 {
-        [4] = { .doit   = dn_dev_rtm_newaddr,  },
-        [5] = { .doit   = dn_dev_rtm_deladdr,  },
-        [6] = { .dumpit = dn_dev_dump_ifaddr,  },
-
+       [RTM_NEWADDR  - RTM_BASE] = { .doit     = dn_dev_rtm_newaddr,   },
+       [RTM_DELADDR  - RTM_BASE] = { .doit     = dn_dev_rtm_deladdr,   },
+       [RTM_GETADDR  - RTM_BASE] = { .dumpit   = dn_dev_dump_ifaddr,   },
 #ifdef CONFIG_DECNET_ROUTER
-        [8] = { .doit   = dn_fib_rtm_newroute, },
-        [9] = { .doit   = dn_fib_rtm_delroute, },
-       [10] = { .doit   = dn_cache_getroute, .dumpit = dn_fib_dump, },
-       [16] = { .doit   = dn_fib_rtm_newrule, },
-       [17] = { .doit   = dn_fib_rtm_delrule, },
-       [18] = { .dumpit = dn_fib_dump_rules,  },
+       [RTM_NEWROUTE - RTM_BASE] = { .doit     = dn_fib_rtm_newroute,  },
+       [RTM_DELROUTE - RTM_BASE] = { .doit     = dn_fib_rtm_delroute,  },
+       [RTM_GETROUTE - RTM_BASE] = { .doit     = dn_cache_getroute,
+                                     .dumpit   = dn_fib_dump,          },
+       [RTM_NEWRULE  - RTM_BASE] = { .doit     = dn_fib_rtm_newrule,   },
+       [RTM_DELRULE  - RTM_BASE] = { .doit     = dn_fib_rtm_delrule,   },
+       [RTM_GETRULE  - RTM_BASE] = { .dumpit   = dn_fib_dump_rules,    },
 #else
-       [10] = { .doit   = dn_cache_getroute, .dumpit = dn_cache_dump, },
+       [RTM_GETROUTE - RTM_BASE] = { .doit     = dn_cache_getroute,
+                                     .dumpit   = dn_cache_dump,        },
 #endif
 
 };
 
 static int __initdata addr[2];
-static int __initdata num;
-module_param_array(addr, int, num, 0444);
+module_param_array(addr, int, NULL, 0444);
 MODULE_PARM_DESC(addr, "The DECnet address of this machine: area,node");
 
 void __init dn_dev_init(void)
@@ -1491,9 +1452,6 @@ void __init dn_dev_init(void)
         decnet_address = dn_htons((addr[0] << 10) | addr[1]);
 
        dn_dev_devices_on();
-#ifdef CONFIG_DECNET_SIOCGIFCONF
-       register_gifconf(PF_DECnet, dnet_gifconf);
-#endif /* CONFIG_DECNET_SIOCGIFCONF */
 
        rtnetlink_links[PF_DECnet] = dnet_rtnetlink_table;
 
@@ -1512,10 +1470,6 @@ void __exit dn_dev_cleanup(void)
 {
        rtnetlink_links[PF_DECnet] = NULL;
 
-#ifdef CONFIG_DECNET_SIOCGIFCONF
-       unregister_gifconf(PF_DECnet);
-#endif /* CONFIG_DECNET_SIOCGIFCONF */
-
 #ifdef CONFIG_SYSCTL
        {
                int i;