Merge branch 'sii-m15w' into upstream
[pandora-kernel.git] / net / xfrm / xfrm_policy.c
index b469c8b..f35bc67 100644 (file)
@@ -13,7 +13,6 @@
  *
  */
 
-#include <linux/config.h>
 #include <linux/slab.h>
 #include <linux/kmod.h>
 #include <linux/list.h>
@@ -46,45 +45,43 @@ 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);
+static struct xfrm_policy_afinfo *xfrm_policy_lock_afinfo(unsigned int family);
+static void xfrm_policy_unlock_afinfo(struct xfrm_policy_afinfo *afinfo);
 
 int xfrm_register_type(struct xfrm_type *type, unsigned short family)
 {
-       struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
-       struct xfrm_type_map *typemap;
+       struct xfrm_policy_afinfo *afinfo = xfrm_policy_lock_afinfo(family);
+       struct xfrm_type **typemap;
        int err = 0;
 
        if (unlikely(afinfo == NULL))
                return -EAFNOSUPPORT;
        typemap = afinfo->type_map;
 
-       write_lock_bh(&typemap->lock);
-       if (likely(typemap->map[type->proto] == NULL))
-               typemap->map[type->proto] = type;
+       if (likely(typemap[type->proto] == NULL))
+               typemap[type->proto] = type;
        else
                err = -EEXIST;
-       write_unlock_bh(&typemap->lock);
-       xfrm_policy_put_afinfo(afinfo);
+       xfrm_policy_unlock_afinfo(afinfo);
        return err;
 }
 EXPORT_SYMBOL(xfrm_register_type);
 
 int xfrm_unregister_type(struct xfrm_type *type, unsigned short family)
 {
-       struct xfrm_policy_afinfo *afinfo = xfrm_policy_get_afinfo(family);
-       struct xfrm_type_map *typemap;
+       struct xfrm_policy_afinfo *afinfo = xfrm_policy_lock_afinfo(family);
+       struct xfrm_type **typemap;
        int err = 0;
 
        if (unlikely(afinfo == NULL))
                return -EAFNOSUPPORT;
        typemap = afinfo->type_map;
 
-       write_lock_bh(&typemap->lock);
-       if (unlikely(typemap->map[type->proto] != type))
+       if (unlikely(typemap[type->proto] != type))
                err = -ENOENT;
        else
-               typemap->map[type->proto] = NULL;
-       write_unlock_bh(&typemap->lock);
-       xfrm_policy_put_afinfo(afinfo);
+               typemap[type->proto] = NULL;
+       xfrm_policy_unlock_afinfo(afinfo);
        return err;
 }
 EXPORT_SYMBOL(xfrm_unregister_type);
@@ -92,7 +89,7 @@ EXPORT_SYMBOL(xfrm_unregister_type);
 struct xfrm_type *xfrm_get_type(u8 proto, unsigned short family)
 {
        struct xfrm_policy_afinfo *afinfo;
-       struct xfrm_type_map *typemap;
+       struct xfrm_type **typemap;
        struct xfrm_type *type;
        int modload_attempted = 0;
 
@@ -102,11 +99,9 @@ retry:
                return NULL;
        typemap = afinfo->type_map;
 
-       read_lock(&typemap->lock);
-       type = typemap->map[proto];
+       type = typemap[proto];
        if (unlikely(type && !try_module_get(type->owner)))
                type = NULL;
-       read_unlock(&typemap->lock);
        if (!type && !modload_attempted) {
                xfrm_policy_put_afinfo(afinfo);
                request_module("xfrm-type-%d-%d",
@@ -142,6 +137,89 @@ void xfrm_put_type(struct xfrm_type *type)
        module_put(type->owner);
 }
 
+int xfrm_register_mode(struct xfrm_mode *mode, int family)
+{
+       struct xfrm_policy_afinfo *afinfo;
+       struct xfrm_mode **modemap;
+       int err;
+
+       if (unlikely(mode->encap >= XFRM_MODE_MAX))
+               return -EINVAL;
+
+       afinfo = xfrm_policy_lock_afinfo(family);
+       if (unlikely(afinfo == NULL))
+               return -EAFNOSUPPORT;
+
+       err = -EEXIST;
+       modemap = afinfo->mode_map;
+       if (likely(modemap[mode->encap] == NULL)) {
+               modemap[mode->encap] = mode;
+               err = 0;
+       }
+
+       xfrm_policy_unlock_afinfo(afinfo);
+       return err;
+}
+EXPORT_SYMBOL(xfrm_register_mode);
+
+int xfrm_unregister_mode(struct xfrm_mode *mode, int family)
+{
+       struct xfrm_policy_afinfo *afinfo;
+       struct xfrm_mode **modemap;
+       int err;
+
+       if (unlikely(mode->encap >= XFRM_MODE_MAX))
+               return -EINVAL;
+
+       afinfo = xfrm_policy_lock_afinfo(family);
+       if (unlikely(afinfo == NULL))
+               return -EAFNOSUPPORT;
+
+       err = -ENOENT;
+       modemap = afinfo->mode_map;
+       if (likely(modemap[mode->encap] == mode)) {
+               modemap[mode->encap] = NULL;
+               err = 0;
+       }
+
+       xfrm_policy_unlock_afinfo(afinfo);
+       return err;
+}
+EXPORT_SYMBOL(xfrm_unregister_mode);
+
+struct xfrm_mode *xfrm_get_mode(unsigned int encap, int family)
+{
+       struct xfrm_policy_afinfo *afinfo;
+       struct xfrm_mode *mode;
+       int modload_attempted = 0;
+
+       if (unlikely(encap >= XFRM_MODE_MAX))
+               return NULL;
+
+retry:
+       afinfo = xfrm_policy_get_afinfo(family);
+       if (unlikely(afinfo == NULL))
+               return NULL;
+
+       mode = afinfo->mode_map[encap];
+       if (unlikely(mode && !try_module_get(mode->owner)))
+               mode = NULL;
+       if (!mode && !modload_attempted) {
+               xfrm_policy_put_afinfo(afinfo);
+               request_module("xfrm-mode-%d-%d", family, encap);
+               modload_attempted = 1;
+               goto retry;
+       }
+
+       xfrm_policy_put_afinfo(afinfo);
+       return mode;
+}
+
+void xfrm_put_mode(struct xfrm_mode *mode)
+{
+       module_put(mode->owner);
+}
+
 static inline unsigned long make_jiffies(long secs)
 {
        if (secs >= (MAX_SCHEDULE_TIMEOUT-1)/HZ)
@@ -229,10 +307,9 @@ struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp)
 {
        struct xfrm_policy *policy;
 
-       policy = kmalloc(sizeof(struct xfrm_policy), gfp);
+       policy = kzalloc(sizeof(struct xfrm_policy), gfp);
 
        if (policy) {
-               memset(policy, 0, sizeof(struct xfrm_policy));
                atomic_set(&policy->refcnt, 1);
                rwlock_init(&policy->lock);
                init_timer(&policy->timer);
@@ -1306,17 +1383,31 @@ static struct xfrm_policy_afinfo *xfrm_policy_get_afinfo(unsigned short family)
                return NULL;
        read_lock(&xfrm_policy_afinfo_lock);
        afinfo = xfrm_policy_afinfo[family];
-       if (likely(afinfo != NULL))
-               read_lock(&afinfo->lock);
-       read_unlock(&xfrm_policy_afinfo_lock);
+       if (unlikely(!afinfo))
+               read_unlock(&xfrm_policy_afinfo_lock);
        return afinfo;
 }
 
 static void xfrm_policy_put_afinfo(struct xfrm_policy_afinfo *afinfo)
 {
-       if (unlikely(afinfo == NULL))
-               return;
-       read_unlock(&afinfo->lock);
+       read_unlock(&xfrm_policy_afinfo_lock);
+}
+
+static struct xfrm_policy_afinfo *xfrm_policy_lock_afinfo(unsigned int family)
+{
+       struct xfrm_policy_afinfo *afinfo;
+       if (unlikely(family >= NPROTO))
+               return NULL;
+       write_lock_bh(&xfrm_policy_afinfo_lock);
+       afinfo = xfrm_policy_afinfo[family];
+       if (unlikely(!afinfo))
+               write_unlock_bh(&xfrm_policy_afinfo_lock);
+       return afinfo;
+}
+
+static void xfrm_policy_unlock_afinfo(struct xfrm_policy_afinfo *afinfo)
+{
+       write_unlock_bh(&xfrm_policy_afinfo_lock);
 }
 
 static int xfrm_dev_event(struct notifier_block *this, unsigned long event, void *ptr)