Merge git://git.kernel.org/pub/scm/linux/kernel/git/holtmann/bluetooth-2.6
[sfrench/cifs-2.6.git] / net / decnet / dn_fib.c
index fa20e2efcfc1b76aa86697c16b66871edf382706..d2bc19d479506de64ca4bf9a9da803a1ea8586d6 100644 (file)
@@ -34,6 +34,7 @@
 #include <net/neighbour.h>
 #include <net/dst.h>
 #include <net/flow.h>
+#include <net/fib_rules.h>
 #include <net/dn.h>
 #include <net/dn_route.h>
 #include <net/dn_fib.h>
 
 #define endfor_nexthops(fi) }
 
-extern int dn_cache_dump(struct sk_buff *skb, struct netlink_callback *cb);
-
 static DEFINE_SPINLOCK(dn_fib_multipath_lock);
 static struct dn_fib_info *dn_fib_info_list;
-static DEFINE_RWLOCK(dn_fib_info_lock);
+static DEFINE_SPINLOCK(dn_fib_info_lock);
 
 static struct
 {
        int error;
        u8 scope;
-} dn_fib_props[RTA_MAX+1] = {
+} dn_fib_props[RTN_MAX+1] = {
        [RTN_UNSPEC] =      { .error = 0,       .scope = RT_SCOPE_NOWHERE },
        [RTN_UNICAST] =     { .error = 0,       .scope = RT_SCOPE_UNIVERSE },
        [RTN_LOCAL] =       { .error = 0,       .scope = RT_SCOPE_HOST },
@@ -79,6 +78,9 @@ static struct
        [RTN_XRESOLVE] =    { .error = -EINVAL, .scope = RT_SCOPE_NOWHERE },
 };
 
+static int dn_fib_sync_down(__le16 local, struct net_device *dev, int force);
+static int dn_fib_sync_up(struct net_device *dev);
+
 void dn_fib_free_info(struct dn_fib_info *fi)
 {
        if (fi->fib_dead == 0) {
@@ -96,7 +98,7 @@ void dn_fib_free_info(struct dn_fib_info *fi)
 
 void dn_fib_release_info(struct dn_fib_info *fi)
 {
-       write_lock(&dn_fib_info_lock);
+       spin_lock(&dn_fib_info_lock);
        if (fi && --fi->fib_treeref == 0) {
                if (fi->fib_next)
                        fi->fib_next->fib_prev = fi->fib_prev;
@@ -107,7 +109,7 @@ void dn_fib_release_info(struct dn_fib_info *fi)
                fi->fib_dead = 1;
                dn_fib_info_put(fi);
        }
-       write_unlock(&dn_fib_info_lock);
+       spin_unlock(&dn_fib_info_lock);
 }
 
 static inline int dn_fib_nh_comp(const struct dn_fib_info *fi, const struct dn_fib_info *ofi)
@@ -274,6 +276,9 @@ struct dn_fib_info *dn_fib_create_info(const struct rtmsg *r, struct dn_kern_rta
        struct dn_fib_info *ofi;
        int nhs = 1;
 
+       if (r->rtm_type > RTN_MAX)
+               goto err_inval;
+
        if (dn_fib_props[r->rtm_type].scope > r->rtm_scope)
                goto err_inval;
 
@@ -378,13 +383,13 @@ link_it:
 
        fi->fib_treeref++;
        atomic_inc(&fi->fib_clntref);
-       write_lock(&dn_fib_info_lock);
+       spin_lock(&dn_fib_info_lock);
        fi->fib_next = dn_fib_info_list;
        fi->fib_prev = NULL;
        if (dn_fib_info_list)
                dn_fib_info_list->fib_prev = fi;
        dn_fib_info_list = fi;
-       write_unlock(&dn_fib_info_lock);
+       spin_unlock(&dn_fib_info_lock);
        return fi;
 
 err_inval:
@@ -490,7 +495,8 @@ static int dn_fib_check_attr(struct rtmsg *r, struct rtattr **rta)
                if (attr) {
                        if (RTA_PAYLOAD(attr) < 4 && RTA_PAYLOAD(attr) != 2)
                                return -EINVAL;
-                       if (i != RTA_MULTIPATH && i != RTA_METRICS)
+                       if (i != RTA_MULTIPATH && i != RTA_METRICS &&
+                           i != RTA_TABLE)
                                rta[i-1] = (struct rtattr *)RTA_DATA(attr);
                }
        }
@@ -498,7 +504,7 @@ static int dn_fib_check_attr(struct rtmsg *r, struct rtattr **rta)
        return 0;
 }
 
-int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+static int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
        struct dn_fib_table *tb;
        struct rtattr **rta = arg;
@@ -507,14 +513,14 @@ int dn_fib_rtm_delroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
        if (dn_fib_check_attr(r, rta))
                return -EINVAL;
 
-       tb = dn_fib_get_table(r->rtm_table, 0);
+       tb = dn_fib_get_table(rtm_get_table(rta, r->rtm_table), 0);
        if (tb)
                return tb->delete(tb, r, (struct dn_kern_rta *)rta, nlh, &NETLINK_CB(skb));
 
        return -ESRCH;
 }
 
-int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
+static int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
 {
        struct dn_fib_table *tb;
        struct rtattr **rta = arg;
@@ -523,46 +529,13 @@ int dn_fib_rtm_newroute(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
        if (dn_fib_check_attr(r, rta))
                return -EINVAL;
 
-       tb = dn_fib_get_table(r->rtm_table, 1);
-       if (tb) 
+       tb = dn_fib_get_table(rtm_get_table(rta, r->rtm_table), 1);
+       if (tb)
                return tb->insert(tb, r, (struct dn_kern_rta *)rta, nlh, &NETLINK_CB(skb));
 
        return -ENOBUFS;
 }
 
-
-int dn_fib_dump(struct sk_buff *skb, struct netlink_callback *cb)
-{
-       int t;
-       int s_t;
-       struct dn_fib_table *tb;
-
-       if (NLMSG_PAYLOAD(cb->nlh, 0) >= sizeof(struct rtmsg) &&
-               ((struct rtmsg *)NLMSG_DATA(cb->nlh))->rtm_flags&RTM_F_CLONED)
-                       return dn_cache_dump(skb, cb);
-
-       s_t = cb->args[0];
-       if (s_t == 0)
-               s_t = cb->args[0] = RT_MIN_TABLE;
-
-       for(t = s_t; t <= RT_TABLE_MAX; t++) {
-               if (t < s_t)
-                       continue;
-               if (t > s_t)
-                       memset(&cb->args[1], 0,
-                              sizeof(cb->args) - sizeof(cb->args[0]));
-               tb = dn_fib_get_table(t, 0);
-               if (tb == NULL)
-                       continue;
-               if (tb->dump(tb, skb, cb) < 0)
-                       break;
-       }
-
-       cb->args[0] = t;
-
-       return skb->len;
-}
-
 static void fib_magic(int cmd, int type, __le16 dst, int dst_len, struct dn_ifaddr *ifa)
 {
        struct dn_fib_table *tb;
@@ -629,7 +602,7 @@ static void dn_fib_del_ifaddr(struct dn_ifaddr *ifa)
 
        /* Scan device list */
        read_lock(&dev_base_lock);
-       for(dev = dev_base; dev; dev = dev->next) {
+       for_each_netdev(dev) {
                dn_db = dev->dn_ptr;
                if (dn_db == NULL)
                        continue;
@@ -682,98 +655,82 @@ static int dn_fib_dnaddr_event(struct notifier_block *this, unsigned long event,
        return NOTIFY_DONE;
 }
 
-int dn_fib_sync_down(__le16 local, struct net_device *dev, int force)
+static int dn_fib_sync_down(__le16 local, struct net_device *dev, int force)
 {
-        int ret = 0;
-        int scope = RT_SCOPE_NOWHERE;
-
-        if (force)
-                scope = -1;
-
-        for_fib_info() {
-                /* 
-                 * This makes no sense for DECnet.... we will almost
-                 * certainly have more than one local address the same
-                 * over all our interfaces. It needs thinking about
-                 * some more.
-                 */
-                if (local && fi->fib_prefsrc == local) {
-                        fi->fib_flags |= RTNH_F_DEAD;
-                        ret++;
-                } else if (dev && fi->fib_nhs) {
-                        int dead = 0;
-
-                        change_nexthops(fi) {
-                                if (nh->nh_flags&RTNH_F_DEAD)
-                                        dead++;
-                                else if (nh->nh_dev == dev &&
-                                                nh->nh_scope != scope) {
+       int ret = 0;
+       int scope = RT_SCOPE_NOWHERE;
+
+       if (force)
+               scope = -1;
+
+       for_fib_info() {
+               /*
+                * This makes no sense for DECnet.... we will almost
+                * certainly have more than one local address the same
+                * over all our interfaces. It needs thinking about
+                * some more.
+                */
+               if (local && fi->fib_prefsrc == local) {
+                       fi->fib_flags |= RTNH_F_DEAD;
+                       ret++;
+               } else if (dev && fi->fib_nhs) {
+                       int dead = 0;
+
+                       change_nexthops(fi) {
+                               if (nh->nh_flags&RTNH_F_DEAD)
+                                       dead++;
+                               else if (nh->nh_dev == dev &&
+                                               nh->nh_scope != scope) {
                                        spin_lock_bh(&dn_fib_multipath_lock);
-                                        nh->nh_flags |= RTNH_F_DEAD;
-                                        fi->fib_power -= nh->nh_power;
-                                        nh->nh_power = 0;
+                                       nh->nh_flags |= RTNH_F_DEAD;
+                                       fi->fib_power -= nh->nh_power;
+                                       nh->nh_power = 0;
                                        spin_unlock_bh(&dn_fib_multipath_lock);
-                                        dead++;
-                                }
-                        } endfor_nexthops(fi)
-                        if (dead == fi->fib_nhs) {
-                                fi->fib_flags |= RTNH_F_DEAD;
-                                ret++;
-                        }
-                }
-        } endfor_fib_info();
-        return ret;
+                                       dead++;
+                               }
+                       } endfor_nexthops(fi)
+                       if (dead == fi->fib_nhs) {
+                               fi->fib_flags |= RTNH_F_DEAD;
+                               ret++;
+                       }
+               }
+       } endfor_fib_info();
+       return ret;
 }
 
 
-int dn_fib_sync_up(struct net_device *dev)
+static int dn_fib_sync_up(struct net_device *dev)
 {
-        int ret = 0;
-
-        if (!(dev->flags&IFF_UP))
-                return 0;
-
-        for_fib_info() {
-                int alive = 0;
-
-                change_nexthops(fi) {
-                        if (!(nh->nh_flags&RTNH_F_DEAD)) {
-                                alive++;
-                                continue;
-                        }
-                        if (nh->nh_dev == NULL || !(nh->nh_dev->flags&IFF_UP))
-                                continue;
-                        if (nh->nh_dev != dev || dev->dn_ptr == NULL)
-                                continue;
-                        alive++;
+       int ret = 0;
+
+       if (!(dev->flags&IFF_UP))
+               return 0;
+
+       for_fib_info() {
+               int alive = 0;
+
+               change_nexthops(fi) {
+                       if (!(nh->nh_flags&RTNH_F_DEAD)) {
+                               alive++;
+                               continue;
+                       }
+                       if (nh->nh_dev == NULL || !(nh->nh_dev->flags&IFF_UP))
+                               continue;
+                       if (nh->nh_dev != dev || dev->dn_ptr == NULL)
+                               continue;
+                       alive++;
                        spin_lock_bh(&dn_fib_multipath_lock);
-                        nh->nh_power = 0;
-                        nh->nh_flags &= ~RTNH_F_DEAD;
+                       nh->nh_power = 0;
+                       nh->nh_flags &= ~RTNH_F_DEAD;
                        spin_unlock_bh(&dn_fib_multipath_lock);
-                } endfor_nexthops(fi);
-
-                if (alive > 0) {
-                        fi->fib_flags &= ~RTNH_F_DEAD;
-                        ret++;
-                }
-        } endfor_fib_info();
-        return ret;
-}
+               } endfor_nexthops(fi);
 
-void dn_fib_flush(void)
-{
-        int flushed = 0;
-        struct dn_fib_table *tb;
-        int id;
-
-        for(id = RT_TABLE_MAX; id > 0; id--) {
-                if ((tb = dn_fib_get_table(id, 0)) == NULL)
-                        continue;
-                flushed += tb->flush(tb);
-        }
-
-        if (flushed)
-                dn_rt_cache_flush(-1);
+               if (alive > 0) {
+                       fi->fib_flags &= ~RTNH_F_DEAD;
+                       ret++;
+               }
+       } endfor_fib_info();
+       return ret;
 }
 
 static struct notifier_block dn_fib_dnaddr_notifier = {
@@ -791,11 +748,13 @@ void __exit dn_fib_cleanup(void)
 
 void __init dn_fib_init(void)
 {
-
        dn_fib_table_init();
        dn_fib_rules_init();
 
        register_dnaddr_notifier(&dn_fib_dnaddr_notifier);
+
+       rtnl_register(PF_DECnet, RTM_NEWROUTE, dn_fib_rtm_newroute, NULL);
+       rtnl_register(PF_DECnet, RTM_DELROUTE, dn_fib_rtm_delroute, NULL);
 }