Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jmorris...
[pandora-kernel.git] / crypto / api.c
index 0444d24..9975a7b 100644 (file)
@@ -300,8 +300,8 @@ static void crypto_exit_ops(struct crypto_tfm *tfm)
        const struct crypto_type *type = tfm->__crt_alg->cra_type;
 
        if (type) {
-               if (type->exit)
-                       type->exit(tfm);
+               if (tfm->exit)
+                       tfm->exit(tfm);
                return;
        }
 
@@ -379,17 +379,16 @@ struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 type,
        if (err)
                goto out_free_tfm;
 
-       if (alg->cra_init && (err = alg->cra_init(tfm))) {
-               if (err == -EAGAIN)
-                       crypto_shoot_alg(alg);
+       if (!tfm->exit && alg->cra_init && (err = alg->cra_init(tfm)))
                goto cra_init_failed;
-       }
 
        goto out;
 
 cra_init_failed:
        crypto_exit_ops(tfm);
 out_free_tfm:
+       if (err == -EAGAIN)
+               crypto_shoot_alg(alg);
        kfree(tfm);
 out_err:
        tfm = ERR_PTR(err);
@@ -404,6 +403,9 @@ EXPORT_SYMBOL_GPL(__crypto_alloc_tfm);
  *     @type: Type of algorithm
  *     @mask: Mask for type comparison
  *
+ *     This function should not be used by new algorithm types.
+ *     Plesae use crypto_alloc_tfm instead.
+ *
  *     crypto_alloc_base() will first attempt to locate an already loaded
  *     algorithm.  If that fails and the kernel supports dynamically loadable
  *     modules, it will then attempt to load a module of the same name or
@@ -450,6 +452,111 @@ err:
        return ERR_PTR(err);
 }
 EXPORT_SYMBOL_GPL(crypto_alloc_base);
+
+struct crypto_tfm *crypto_create_tfm(struct crypto_alg *alg,
+                                    const struct crypto_type *frontend)
+{
+       char *mem;
+       struct crypto_tfm *tfm = NULL;
+       unsigned int tfmsize;
+       unsigned int total;
+       int err = -ENOMEM;
+
+       tfmsize = frontend->tfmsize;
+       total = tfmsize + sizeof(*tfm) + frontend->extsize(alg, frontend);
+
+       mem = kzalloc(total, GFP_KERNEL);
+       if (mem == NULL)
+               goto out_err;
+
+       tfm = (struct crypto_tfm *)(mem + tfmsize);
+       tfm->__crt_alg = alg;
+
+       err = frontend->init_tfm(tfm, frontend);
+       if (err)
+               goto out_free_tfm;
+
+       if (!tfm->exit && alg->cra_init && (err = alg->cra_init(tfm)))
+               goto cra_init_failed;
+
+       goto out;
+
+cra_init_failed:
+       crypto_exit_ops(tfm);
+out_free_tfm:
+       if (err == -EAGAIN)
+               crypto_shoot_alg(alg);
+       kfree(mem);
+out_err:
+       tfm = ERR_PTR(err);
+out:
+       return tfm;
+}
+EXPORT_SYMBOL_GPL(crypto_create_tfm);
+
+/*
+ *     crypto_alloc_tfm - Locate algorithm and allocate transform
+ *     @alg_name: Name of algorithm
+ *     @frontend: Frontend algorithm type
+ *     @type: Type of algorithm
+ *     @mask: Mask for type comparison
+ *
+ *     crypto_alloc_tfm() will first attempt to locate an already loaded
+ *     algorithm.  If that fails and the kernel supports dynamically loadable
+ *     modules, it will then attempt to load a module of the same name or
+ *     alias.  If that fails it will send a query to any loaded crypto manager
+ *     to construct an algorithm on the fly.  A refcount is grabbed on the
+ *     algorithm which is then associated with the new transform.
+ *
+ *     The returned transform is of a non-determinate type.  Most people
+ *     should use one of the more specific allocation functions such as
+ *     crypto_alloc_blkcipher.
+ *
+ *     In case of error the return value is an error pointer.
+ */
+struct crypto_tfm *crypto_alloc_tfm(const char *alg_name,
+                                   const struct crypto_type *frontend,
+                                   u32 type, u32 mask)
+{
+       struct crypto_alg *(*lookup)(const char *name, u32 type, u32 mask);
+       struct crypto_tfm *tfm;
+       int err;
+
+       type &= frontend->maskclear;
+       mask &= frontend->maskclear;
+       type |= frontend->type;
+       mask |= frontend->maskset;
+
+       lookup = frontend->lookup ?: crypto_alg_mod_lookup;
+
+       for (;;) {
+               struct crypto_alg *alg;
+
+               alg = lookup(alg_name, type, mask);
+               if (IS_ERR(alg)) {
+                       err = PTR_ERR(alg);
+                       goto err;
+               }
+
+               tfm = crypto_create_tfm(alg, frontend);
+               if (!IS_ERR(tfm))
+                       return tfm;
+
+               crypto_mod_put(alg);
+               err = PTR_ERR(tfm);
+
+err:
+               if (err != -EAGAIN)
+                       break;
+               if (signal_pending(current)) {
+                       err = -EINTR;
+                       break;
+               }
+       }
+
+       return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(crypto_alloc_tfm);
  
 /*
  *     crypto_free_tfm - Free crypto transform
@@ -469,7 +576,7 @@ void crypto_free_tfm(struct crypto_tfm *tfm)
        alg = tfm->__crt_alg;
        size = sizeof(*tfm) + alg->cra_ctxsize;
 
-       if (alg->cra_exit)
+       if (!tfm->exit && alg->cra_exit)
                alg->cra_exit(tfm);
        crypto_exit_ops(tfm);
        crypto_mod_put(alg);