upgrade to fedora-2.6.12-1.1398.FC4 + vserver 2.0.rc7
[linux-2.6.git] / net / xfrm / xfrm_policy.c
index 0bc92ef..d07f5ce 100644 (file)
@@ -13,6 +13,7 @@
  *     
  */
 
+#include <asm/bug.h>
 #include <linux/config.h>
 #include <linux/slab.h>
 #include <linux/kmod.h>
 #include <linux/workqueue.h>
 #include <linux/notifier.h>
 #include <linux/netdevice.h>
+#include <linux/module.h>
 #include <net/xfrm.h>
 #include <net/ip.h>
 
 DECLARE_MUTEX(xfrm_cfg_sem);
+EXPORT_SYMBOL(xfrm_cfg_sem);
 
-static rwlock_t xfrm_policy_lock = RW_LOCK_UNLOCKED;
+static DEFINE_RWLOCK(xfrm_policy_lock);
 
 struct xfrm_policy *xfrm_policy_list[XFRM_POLICY_MAX*2];
+EXPORT_SYMBOL(xfrm_policy_list);
 
-static rwlock_t xfrm_policy_afinfo_lock = RW_LOCK_UNLOCKED;
+static DEFINE_RWLOCK(xfrm_policy_afinfo_lock);
 static struct xfrm_policy_afinfo *xfrm_policy_afinfo[NPROTO];
 
-kmem_cache_t *xfrm_dst_cache;
+static kmem_cache_t *xfrm_dst_cache;
 
 static struct work_struct xfrm_policy_gc_work;
 static struct list_head xfrm_policy_gc_list =
        LIST_HEAD_INIT(xfrm_policy_gc_list);
-static spinlock_t xfrm_policy_gc_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(xfrm_policy_gc_lock);
 
 static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family);
 static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo);
@@ -62,6 +66,7 @@ int xfrm_register_type(struct xfrm_type *type, unsigned short family)
        xfrm_policy_put_afinfo(afinfo);
        return err;
 }
+EXPORT_SYMBOL(xfrm_register_type);
 
 int xfrm_unregister_type(struct xfrm_type *type, unsigned short family)
 {
@@ -82,6 +87,7 @@ int xfrm_unregister_type(struct xfrm_type *type, unsigned short family)
        xfrm_policy_put_afinfo(afinfo);
        return err;
 }
+EXPORT_SYMBOL(xfrm_unregister_type);
 
 struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family)
 {
@@ -112,6 +118,7 @@ retry:
        xfrm_policy_put_afinfo(afinfo);
        return type;
 }
+EXPORT_SYMBOL(xfrm_get_type);
 
 int xfrm_dst_lookup(struct xfrm_dst **dst, struct flowi *fl, 
                    unsigned short family)
@@ -129,6 +136,7 @@ int xfrm_dst_lookup(struct xfrm_dst **dst, struct flowi *fl,
        xfrm_policy_put_afinfo(afinfo);
        return err;
 }
+EXPORT_SYMBOL(xfrm_dst_lookup);
 
 void xfrm_put_type(struct xfrm_type *type)
 {
@@ -234,6 +242,7 @@ struct xfrm_policy *xfrm_policy_alloc(int gfp)
        }
        return policy;
 }
+EXPORT_SYMBOL(xfrm_policy_alloc);
 
 /* Destroy xfrm_policy: descendant resources must be released to this moment. */
 
@@ -250,6 +259,7 @@ void __xfrm_policy_destroy(struct xfrm_policy *policy)
 
        kfree(policy);
 }
+EXPORT_SYMBOL(__xfrm_policy_destroy);
 
 static void xfrm_policy_gc_kill(struct xfrm_policy *policy)
 {
@@ -291,19 +301,23 @@ static void xfrm_policy_gc_task(void *data)
 
 static void xfrm_policy_kill(struct xfrm_policy *policy)
 {
-       write_lock_bh(&policy->lock);
-       if (policy->dead)
-               goto out;
+       int dead;
 
+       write_lock_bh(&policy->lock);
+       dead = policy->dead;
        policy->dead = 1;
+       write_unlock_bh(&policy->lock);
+
+       if (unlikely(dead)) {
+               WARN_ON(1);
+               return;
+       }
 
        spin_lock(&xfrm_policy_gc_lock);
        list_add(&policy->list, &xfrm_policy_gc_list);
        spin_unlock(&xfrm_policy_gc_lock);
-       schedule_work(&xfrm_policy_gc_work);
 
-out:
-       write_unlock_bh(&policy->lock);
+       schedule_work(&xfrm_policy_gc_work);
 }
 
 /* Generate new index... KAME seems to generate them ordered by cost
@@ -373,6 +387,7 @@ int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl)
        }
        return 0;
 }
+EXPORT_SYMBOL(xfrm_policy_insert);
 
 struct xfrm_policy *xfrm_policy_bysel(int dir, struct xfrm_selector *sel,
                                      int delete)
@@ -396,6 +411,7 @@ struct xfrm_policy *xfrm_policy_bysel(int dir, struct xfrm_selector *sel,
        }
        return pol;
 }
+EXPORT_SYMBOL(xfrm_policy_bysel);
 
 struct xfrm_policy *xfrm_policy_byid(int dir, u32 id, int delete)
 {
@@ -418,6 +434,7 @@ struct xfrm_policy *xfrm_policy_byid(int dir, u32 id, int delete)
        }
        return pol;
 }
+EXPORT_SYMBOL(xfrm_policy_byid);
 
 void xfrm_policy_flush(void)
 {
@@ -438,6 +455,7 @@ void xfrm_policy_flush(void)
        atomic_inc(&flow_cache_genid);
        write_unlock_bh(&xfrm_policy_lock);
 }
+EXPORT_SYMBOL(xfrm_policy_flush);
 
 int xfrm_policy_walk(int (*func)(struct xfrm_policy *, int, int, void*),
                     void *data)
@@ -470,7 +488,7 @@ out:
        read_unlock_bh(&xfrm_policy_lock);
        return error;
 }
-
+EXPORT_SYMBOL(xfrm_policy_walk);
 
 /* Find policy to apply to this flow. */
 
@@ -498,7 +516,7 @@ static void xfrm_policy_lookup(struct flowi *fl, u16 family, u8 dir,
                *obj_refp = &pol->refcnt;
 }
 
-struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struct flowi *fl)
+static struct xfrm_policy *xfrm_sk_policy_lookup(struct sock *sk, int dir, struct flowi *fl)
 {
        struct xfrm_policy *pol;
 
@@ -845,6 +863,7 @@ error:
        *dst_p = NULL;
        return err;
 }
+EXPORT_SYMBOL(xfrm_lookup);
 
 /* When skb is transformed back to its "native" form, we have to
  * check policy restrictions. At the moment we make this in maximally
@@ -981,6 +1000,7 @@ reject:
        xfrm_pol_put(pol);
        return 0;
 }
+EXPORT_SYMBOL(__xfrm_policy_check);
 
 int __xfrm_route_forward(struct sk_buff *skb, unsigned short family)
 {
@@ -991,6 +1011,7 @@ int __xfrm_route_forward(struct sk_buff *skb, unsigned short family)
 
        return xfrm_lookup(&skb->dst, &fl, NULL, 0) == 0;
 }
+EXPORT_SYMBOL(__xfrm_route_forward);
 
 /* Optimize later using cookies and generation ids. */
 
@@ -999,33 +1020,23 @@ static struct dst_entry *xfrm_dst_check(struct dst_entry *dst, u32 cookie)
        if (!stale_bundle(dst))
                return dst;
 
-       dst_release(dst);
        return NULL;
 }
 
 static int stale_bundle(struct dst_entry *dst)
 {
-       struct dst_entry *child = dst;
-
-       while (child) {
-               if (child->obsolete > 0 ||
-                   (child->dev && !netif_running(child->dev)) ||
-                   (child->xfrm && child->xfrm->km.state != XFRM_STATE_VALID)) {
-                       return 1;
-               }
-               child = child->child;
-       }
-
-       return 0;
+       return !xfrm_bundle_ok((struct xfrm_dst *)dst, NULL, AF_UNSPEC);
 }
 
-static void xfrm_dst_destroy(struct dst_entry *dst)
+void xfrm_dst_ifdown(struct dst_entry *dst, struct net_device *dev)
 {
-       if (!dst->xfrm)
-               return;
-       xfrm_state_put(dst->xfrm);
-       dst->xfrm = NULL;
+       while ((dst = dst->child) && dst->xfrm && dst->dev == dev) {
+               dst->dev = &loopback_dev;
+               dev_hold(&loopback_dev);
+               dev_put(dev);
+       }
 }
+EXPORT_SYMBOL(xfrm_dst_ifdown);
 
 static void xfrm_link_failure(struct sk_buff *skb)
 {
@@ -1092,6 +1103,94 @@ int xfrm_flush_bundles(void)
        return 0;
 }
 
+void xfrm_init_pmtu(struct dst_entry *dst)
+{
+       do {
+               struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
+               u32 pmtu, route_mtu_cached;
+
+               pmtu = dst_mtu(dst->child);
+               xdst->child_mtu_cached = pmtu;
+
+               pmtu = xfrm_state_mtu(dst->xfrm, pmtu);
+
+               route_mtu_cached = dst_mtu(xdst->route);
+               xdst->route_mtu_cached = route_mtu_cached;
+
+               if (pmtu > route_mtu_cached)
+                       pmtu = route_mtu_cached;
+
+               dst->metrics[RTAX_MTU-1] = pmtu;
+       } while ((dst = dst->next));
+}
+
+EXPORT_SYMBOL(xfrm_init_pmtu);
+
+/* Check that the bundle accepts the flow and its components are
+ * still valid.
+ */
+
+int xfrm_bundle_ok(struct xfrm_dst *first, struct flowi *fl, int family)
+{
+       struct dst_entry *dst = &first->u.dst;
+       struct xfrm_dst *last;
+       u32 mtu;
+
+       if (!dst_check(dst->path, ((struct xfrm_dst *)dst)->path_cookie) ||
+           (dst->dev && !netif_running(dst->dev)))
+               return 0;
+
+       last = NULL;
+
+       do {
+               struct xfrm_dst *xdst = (struct xfrm_dst *)dst;
+
+               if (fl && !xfrm_selector_match(&dst->xfrm->sel, fl, family))
+                       return 0;
+               if (dst->xfrm->km.state != XFRM_STATE_VALID)
+                       return 0;
+
+               mtu = dst_mtu(dst->child);
+               if (xdst->child_mtu_cached != mtu) {
+                       last = xdst;
+                       xdst->child_mtu_cached = mtu;
+               }
+
+               if (!dst_check(xdst->route, xdst->route_cookie))
+                       return 0;
+               mtu = dst_mtu(xdst->route);
+               if (xdst->route_mtu_cached != mtu) {
+                       last = xdst;
+                       xdst->route_mtu_cached = mtu;
+               }
+
+               dst = dst->child;
+       } while (dst->xfrm);
+
+       if (likely(!last))
+               return 1;
+
+       mtu = last->child_mtu_cached;
+       for (;;) {
+               dst = &last->u.dst;
+
+               mtu = xfrm_state_mtu(dst->xfrm, mtu);
+               if (mtu > last->route_mtu_cached)
+                       mtu = last->route_mtu_cached;
+               dst->metrics[RTAX_MTU-1] = mtu;
+
+               if (last == first)
+                       break;
+
+               last = last->u.next;
+               last->child_mtu_cached = mtu;
+       }
+
+       return 1;
+}
+
+EXPORT_SYMBOL(xfrm_bundle_ok);
+
 /* Well... that's _TASK_. We need to scan through transformation
  * list and figure out what mss tcp should generate in order to
  * final datagram fit to mtu. Mama mia... :-)
@@ -1148,8 +1247,6 @@ int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo)
                        dst_ops->kmem_cachep = xfrm_dst_cache;
                if (likely(dst_ops->check == NULL))
                        dst_ops->check = xfrm_dst_check;
-               if (likely(dst_ops->destroy == NULL))
-                       dst_ops->destroy = xfrm_dst_destroy;
                if (likely(dst_ops->negative_advice == NULL))
                        dst_ops->negative_advice = xfrm_negative_advice;
                if (likely(dst_ops->link_failure == NULL))
@@ -1163,6 +1260,7 @@ int xfrm_policy_register_afinfo(struct xfrm_policy_afinfo *afinfo)
        write_unlock(&xfrm_policy_afinfo_lock);
        return err;
 }
+EXPORT_SYMBOL(xfrm_policy_register_afinfo);
 
 int xfrm_policy_unregister_afinfo(struct xfrm_policy_afinfo *afinfo)
 {
@@ -1180,7 +1278,6 @@ int xfrm_policy_unregister_afinfo(struct xfrm_policy_afinfo *afinfo)
                        xfrm_policy_afinfo[afinfo->family] = NULL;
                        dst_ops->kmem_cachep = NULL;
                        dst_ops->check = NULL;
-                       dst_ops->destroy = NULL;
                        dst_ops->negative_advice = NULL;
                        dst_ops->link_failure = NULL;
                        dst_ops->get_mss = NULL;
@@ -1190,6 +1287,7 @@ int xfrm_policy_unregister_afinfo(struct xfrm_policy_afinfo *afinfo)
        write_unlock(&xfrm_policy_afinfo_lock);
        return err;
 }
+EXPORT_SYMBOL(xfrm_policy_unregister_afinfo);
 
 static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family)
 {
@@ -1220,13 +1318,13 @@ static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void
        return NOTIFY_DONE;
 }
 
-struct notifier_block xfrm_dev_notifier = {
+static struct notifier_block xfrm_dev_notifier = {
        xfrm_dev_event,
        NULL,
        0
 };
 
-void __init xfrm_policy_init(void)
+static void __init xfrm_policy_init(void)
 {
        xfrm_dst_cache = kmem_cache_create("xfrm_dst_cache",
                                           sizeof(struct xfrm_dst),