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 / ipv4 / fib_frontend.c
index 563e7d6..cdde963 100644 (file)
@@ -20,6 +20,7 @@
 #include <asm/uaccess.h>
 #include <asm/system.h>
 #include <linux/bitops.h>
+#include <linux/capability.h>
 #include <linux/types.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
@@ -30,6 +31,7 @@
 #include <linux/errno.h>
 #include <linux/in.h>
 #include <linux/inet.h>
+#include <linux/inetdevice.h>
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/skbuff.h>
@@ -173,7 +175,7 @@ int fib_validate_source(u32 src, u32 dst, u8 tos, int oif,
 
        no_addr = rpf = 0;
        rcu_read_lock();
-       in_dev = __in_dev_get(dev);
+       in_dev = __in_dev_get_rcu(dev);
        if (in_dev) {
                no_addr = in_dev->ifa_list == NULL;
                rpf = IN_DEV_RPFILTER(in_dev);
@@ -266,8 +268,7 @@ int ip_rt_ioctl(unsigned int cmd, void __user *arg)
                                if (tb)
                                        err = tb->tb_insert(tb, &req.rtm, &rta, &req.nlh, NULL);
                        }
-                       if (rta.rta_mx)
-                               kfree(rta.rta_mx);
+                       kfree(rta.rta_mx);
                }
                rtnl_unlock();
                return err;
@@ -288,13 +289,13 @@ static int inet_check_attr(struct rtmsg *r, struct rtattr **rta)
 {
        int i;
 
-       for (i=1; i<=RTA_MAX; i++) {
-               struct rtattr *attr = rta[i-1];
+       for (i=1; i<=RTA_MAX; i++, rta++) {
+               struct rtattr *attr = *rta;
                if (attr) {
                        if (RTA_PAYLOAD(attr) < 4)
                                return -EINVAL;
                        if (i != RTA_MULTIPATH && i != RTA_METRICS)
-                               rta[i-1] = (struct rtattr*)RTA_DATA(attr);
+                               *rta = (struct rtattr*)RTA_DATA(attr);
                }
        }
        return 0;
@@ -408,7 +409,7 @@ static void fib_magic(int cmd, int type, u32 dst, int dst_len, struct in_ifaddr
                tb->tb_delete(tb, &req.rtm, &rta, &req.nlh, NULL);
 }
 
-static void fib_add_ifaddr(struct in_ifaddr *ifa)
+void fib_add_ifaddr(struct in_ifaddr *ifa)
 {
        struct in_device *in_dev = ifa->ifa_dev;
        struct net_device *dev = in_dev->dev;
@@ -516,6 +517,63 @@ static void fib_del_ifaddr(struct in_ifaddr *ifa)
 #undef BRD1_OK
 }
 
+static void nl_fib_lookup(struct fib_result_nl *frn, struct fib_table *tb )
+{
+       
+       struct fib_result       res;
+       struct flowi            fl = { .nl_u = { .ip4_u = { .daddr = frn->fl_addr, 
+                                                           .fwmark = frn->fl_fwmark,
+                                                           .tos = frn->fl_tos,
+                                                           .scope = frn->fl_scope } } };
+       if (tb) {
+               local_bh_disable();
+
+               frn->tb_id = tb->tb_id;
+               frn->err = tb->tb_lookup(tb, &fl, &res);
+
+               if (!frn->err) {
+                       frn->prefixlen = res.prefixlen;
+                       frn->nh_sel = res.nh_sel;
+                       frn->type = res.type;
+                       frn->scope = res.scope;
+               }
+               local_bh_enable();
+       }
+}
+
+static void nl_fib_input(struct sock *sk, int len)
+{
+       struct sk_buff *skb = NULL;
+        struct nlmsghdr *nlh = NULL;
+       struct fib_result_nl *frn;
+       u32 pid;     
+       struct fib_table *tb;
+       
+       skb = skb_dequeue(&sk->sk_receive_queue);
+       nlh = (struct nlmsghdr *)skb->data;
+       if (skb->len < NLMSG_SPACE(0) || skb->len < nlh->nlmsg_len ||
+           nlh->nlmsg_len < NLMSG_LENGTH(sizeof(*frn))) {
+               kfree_skb(skb);
+               return;
+       }
+       
+       frn = (struct fib_result_nl *) NLMSG_DATA(nlh);
+       tb = fib_get_table(frn->tb_id_in);
+
+       nl_fib_lookup(frn, tb);
+       
+       pid = nlh->nlmsg_pid;           /*pid of sending process */
+       NETLINK_CB(skb).pid = 0;         /* from kernel */
+       NETLINK_CB(skb).dst_pid = pid;
+       NETLINK_CB(skb).dst_group = 0;  /* unicast */
+       netlink_unicast(sk, skb, pid, MSG_DONTWAIT);
+}    
+
+static void nl_fib_lookup_init(void)
+{
+      netlink_kernel_create(NETLINK_FIB_LOOKUP, 0, nl_fib_input, THIS_MODULE);
+}
+
 static void fib_disable_ip(struct net_device *dev, int force)
 {
        if (fib_sync_down(0, dev, force))
@@ -538,7 +596,7 @@ static int fib_inetaddr_event(struct notifier_block *this, unsigned long event,
                break;
        case NETDEV_DOWN:
                fib_del_ifaddr(ifa);
-               if (ifa->ifa_dev && ifa->ifa_dev->ifa_list == NULL) {
+               if (ifa->ifa_dev->ifa_list == NULL) {
                        /* Last address was deleted from this interface.
                           Disable IP.
                         */
@@ -554,7 +612,7 @@ static int fib_inetaddr_event(struct notifier_block *this, unsigned long event,
 static int fib_netdev_event(struct notifier_block *this, unsigned long event, void *ptr)
 {
        struct net_device *dev = ptr;
-       struct in_device *in_dev = __in_dev_get(dev);
+       struct in_device *in_dev = __in_dev_get_rtnl(dev);
 
        if (event == NETDEV_UNREGISTER) {
                fib_disable_ip(dev, 2);
@@ -604,8 +662,7 @@ void __init ip_fib_init(void)
 
        register_netdevice_notifier(&fib_netdev_notifier);
        register_inetaddr_notifier(&fib_inetaddr_notifier);
+       nl_fib_lookup_init();
 }
 
 EXPORT_SYMBOL(inet_addr_type);
-EXPORT_SYMBOL(ip_dev_find);
-EXPORT_SYMBOL(ip_rt_ioctl);