Fedora kernel-2.6.17-1.2142_FC4 patched with stable patch-2.6.17.4-vs2.0.2-rc26.diff
[linux-2.6.git] / net / decnet / dn_dev.c
index 11b0f0c..a26ff9f 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>
@@ -62,11 +64,11 @@ extern struct neigh_table dn_neigh_table;
 /*
  * decnet_address is kept in network order.
  */
-dn_address decnet_address = 0;
+__le16 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;
+static BLOCKING_NOTIFIER_HEAD(dnaddr_chain);
 
 static struct dn_dev *dn_dev_create(struct net_device *dev, int *err);
 static void dn_dev_delete(struct net_device *dev);
@@ -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,52 +301,6 @@ 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 __user *buffer,
@@ -454,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;
@@ -483,14 +439,14 @@ static void dn_dev_del_ifa(struct dn_dev *dn_db, struct dn_ifaddr **ifap, int de
        *ifap = ifa1->ifa_next;
 
        if (dn_db->dev->type == ARPHRD_ETHER) {
-               if (ifa1->ifa_local != dn_htons(dn_eth2dn(dev->dev_addr))) {
+               if (ifa1->ifa_local != dn_eth2dn(dev->dev_addr)) {
                        dn_dn2eth(mac_addr, ifa1->ifa_local);
                        dev_mc_delete(dev, mac_addr, ETH_ALEN, 0);
                }
        }
 
        rtmsg_ifa(RTM_DELADDR, ifa1);
-       notifier_call_chain(&dnaddr_chain, NETDEV_DOWN, ifa1);
+       blocking_notifier_call_chain(&dnaddr_chain, NETDEV_DOWN, ifa1);
        if (destroy) {
                dn_dev_free_ifa(ifa1);
 
@@ -514,7 +470,7 @@ static int dn_dev_insert_ifa(struct dn_dev *dn_db, struct dn_ifaddr *ifa)
        }
 
        if (dev->type == ARPHRD_ETHER) {
-               if (ifa->ifa_local != dn_htons(dn_eth2dn(dev->dev_addr))) {
+               if (ifa->ifa_local != dn_eth2dn(dev->dev_addr)) {
                        dn_dn2eth(mac_addr, ifa->ifa_local);
                        dev_mc_add(dev, mac_addr, ETH_ALEN, 0);
                        dev_mc_upload(dev);
@@ -525,7 +481,7 @@ static int dn_dev_insert_ifa(struct dn_dev *dn_db, struct dn_ifaddr *ifa)
        dn_db->ifa_list = ifa;
 
        rtmsg_ifa(RTM_NEWADDR, ifa);
-       notifier_call_chain(&dnaddr_chain, NETDEV_UP, ifa);
+       blocking_notifier_call_chain(&dnaddr_chain, NETDEV_UP, ifa);
 
        return 0;
 }
@@ -605,7 +561,7 @@ int dn_dev_ioctl(unsigned int cmd, void __user *arg)
 
        switch(cmd) {
                case SIOCGIFADDR:
-                       *((dn_address *)sdn->sdn_nodeaddr) = ifa->ifa_local;
+                       *((__le16 *)sdn->sdn_nodeaddr) = ifa->ifa_local;
                        goto rarok;
 
                case SIOCSIFADDR:
@@ -635,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(old);
+       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;
@@ -661,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);
@@ -704,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);
 
@@ -715,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;
@@ -751,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)
@@ -789,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;
                }
        }
@@ -801,7 +804,7 @@ done:
        return skb->len;
 }
 
-static int dn_dev_get_first(struct net_device *dev, dn_address *addr)
+static int dn_dev_get_first(struct net_device *dev, __le16 *addr)
 {
        struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr;
        struct dn_ifaddr *ifa;
@@ -827,7 +830,7 @@ out:
  * a sensible default. Eventually the routing code will take care of all the
  * nasties for us I hope.
  */
-int dn_dev_bind_default(dn_address *addr)
+int dn_dev_bind_default(__le16 *addr)
 {
        struct net_device *dev;
        int rv;
@@ -850,7 +853,7 @@ static void dn_send_endnode_hello(struct net_device *dev, struct dn_ifaddr *ifa)
 {
         struct endnode_hello_message *msg;
         struct sk_buff *skb = NULL;
-        unsigned short int *pktlen;
+        __le16 *pktlen;
        struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr;
 
         if ((skb = dn_alloc_skb(NULL, sizeof(*msg), GFP_ATOMIC)) == NULL)
@@ -879,7 +882,7 @@ static void dn_send_endnode_hello(struct net_device *dev, struct dn_ifaddr *ifa)
         msg->datalen = 0x02;
         memset(msg->data, 0xAA, 2);
         
-        pktlen = (unsigned short *)skb_push(skb,2);
+        pktlen = (__le16 *)skb_push(skb,2);
         *pktlen = dn_htons(skb->len - 2);
 
        skb->nh.raw = skb->data;
@@ -923,7 +926,7 @@ static void dn_send_router_hello(struct net_device *dev, struct dn_ifaddr *ifa)
        size_t size;
        unsigned char *ptr;
        unsigned char *i1, *i2;
-       unsigned short *pktlen;
+       __le16 *pktlen;
        char *src;
 
        if (mtu2blksize(dev) < (26 + 7))
@@ -952,11 +955,11 @@ static void dn_send_router_hello(struct net_device *dev, struct dn_ifaddr *ifa)
        ptr += ETH_ALEN;
        *ptr++ = dn_db->parms.forwarding == 1 ? 
                        DN_RT_INFO_L1RT : DN_RT_INFO_L2RT;
-       *((unsigned short *)ptr) = dn_htons(mtu2blksize(dev));
+       *((__le16 *)ptr) = dn_htons(mtu2blksize(dev));
        ptr += 2;
        *ptr++ = dn_db->parms.priority; /* Priority */ 
        *ptr++ = 0; /* Area: Reserved */
-       *((unsigned short *)ptr) = dn_htons((unsigned short)dn_db->parms.t3);
+       *((__le16 *)ptr) = dn_htons((unsigned short)dn_db->parms.t3);
        ptr += 2;
        *ptr++ = 0; /* MPD: Reserved */
        i1 = ptr++;
@@ -971,7 +974,7 @@ static void dn_send_router_hello(struct net_device *dev, struct dn_ifaddr *ifa)
 
        skb_trim(skb, (27 + *i2));
 
-       pktlen = (unsigned short *)skb_push(skb, 2);
+       pktlen = (__le16 *)skb_push(skb, 2);
        *pktlen = dn_htons(skb->len - 2);
 
        skb->nh.raw = skb->data;
@@ -1013,7 +1016,7 @@ static void dn_send_ptp_hello(struct net_device *dev, struct dn_ifaddr *ifa)
        ptr = skb_put(skb, 2 + 4 + tdlen);
 
        *ptr++ = DN_RT_PKT_HELO;
-       *((dn_address *)ptr) = ifa->ifa_local;
+       *((__le16 *)ptr) = ifa->ifa_local;
        ptr += 2;
        *ptr++ = tdlen;
 
@@ -1108,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);
@@ -1146,7 +1150,7 @@ struct dn_dev *dn_dev_create(struct net_device *dev, int *err)
 void dn_dev_up(struct net_device *dev)
 {
        struct dn_ifaddr *ifa;
-       dn_address addr = decnet_address;
+       __le16 addr = decnet_address;
        int maybe_default = 0;
        struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr;
 
@@ -1169,7 +1173,7 @@ void dn_dev_up(struct net_device *dev)
        if (dev->type == ARPHRD_ETHER) {
                if (memcmp(dev->dev_addr, dn_hiord, 4) != 0)
                        return;
-               addr = dn_htons(dn_eth2dn(dev->dev_addr));
+               addr = dn_eth2dn(dev->dev_addr);
                maybe_default = 1;
        }
 
@@ -1215,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);
@@ -1280,67 +1285,14 @@ void dn_dev_devices_on(void)
 
 int register_dnaddr_notifier(struct notifier_block *nb)
 {
-       return notifier_chain_register(&dnaddr_chain, nb);
+       return blocking_notifier_chain_register(&dnaddr_chain, nb);
 }
 
 int unregister_dnaddr_notifier(struct notifier_block *nb)
 {
-       return notifier_chain_unregister(&dnaddr_chain, nb);
+       return blocking_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 __user *buf, int len)
-{
-       struct dn_dev *dn_db = (struct dn_dev *)dev->dn_ptr;
-       struct dn_ifaddr *ifa;
-       char buffer[DN_IFREQ_SIZE];
-       struct ifreq *ifr = (struct ifreq *)buffer;
-       struct sockaddr_dn *addr = (struct sockaddr_dn *)&ifr->ifr_addr;
-       int done = 0;
-
-       if ((dn_db == NULL) || ((ifa = dn_db->ifa_list) == NULL))
-               return 0;
-
-       for(; ifa; ifa = ifa->ifa_next) {
-               if (!buf) {
-                       done += sizeof(DN_IFREQ_SIZE);
-                       continue;
-               }
-               if (len < DN_IFREQ_SIZE)
-                       return done;
-               memset(buffer, 0, DN_IFREQ_SIZE);
-
-               if (ifa->ifa_label)
-                       strcpy(ifr->ifr_name, ifa->ifa_label);
-               else
-                       strcpy(ifr->ifr_name, dev->name);
-
-               addr->sdn_family = AF_DECnet;
-               addr->sdn_add.a_len = 2;
-               memcpy(addr->sdn_add.a_addr, &ifa->ifa_local,
-                       sizeof(dn_address));
-
-               if (copy_to_user(buf, buffer, DN_IFREQ_SIZE)) {
-                       done = -EFAULT;
-                       break;
-               }
-
-               buf  += 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)
 {
@@ -1433,8 +1385,8 @@ static int dn_dev_seq_show(struct seq_file *seq, void *v)
                                mtu2blksize(dev),
                                dn_db->parms.priority,
                                dn_db->parms.state, dn_db->parms.name,
-                               dn_db->router ? dn_addr2asc(dn_ntohs(*(dn_address *)dn_db->router->primary_key), router_buf) : "",
-                               dn_db->peer ? dn_addr2asc(dn_ntohs(*(dn_address *)dn_db->peer->primary_key), peer_buf) : "");
+                               dn_db->router ? dn_addr2asc(dn_ntohs(*(__le16 *)dn_db->router->primary_key), router_buf) : "",
+                               dn_db->peer ? dn_addr2asc(dn_ntohs(*(__le16 *)dn_db->peer->primary_key), peer_buf) : "");
        }
        return 0;
 }
@@ -1461,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)
@@ -1500,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;
 
@@ -1521,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;