[CRYPTO] api: Add async blkcipher type
[linux-2.6.git] / crypto / algapi.c
index 36c4f1b..1c2185b 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/module.h>
+#include <linux/rtnetlink.h>
 #include <linux/string.h>
 
 #include "internal.h"
@@ -376,7 +377,8 @@ void crypto_drop_spawn(struct crypto_spawn *spawn)
 }
 EXPORT_SYMBOL_GPL(crypto_drop_spawn);
 
-struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn)
+struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn, u32 type,
+                                   u32 mask)
 {
        struct crypto_alg *alg;
        struct crypto_alg *alg2;
@@ -395,11 +397,19 @@ struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn)
                return ERR_PTR(-EAGAIN);
        }
 
-       tfm = __crypto_alloc_tfm(alg, 0);
+       tfm = ERR_PTR(-EINVAL);
+       if (unlikely((alg->cra_flags ^ type) & mask))
+               goto out_put_alg;
+
+       tfm = __crypto_alloc_tfm(alg, type, mask);
        if (IS_ERR(tfm))
-               crypto_mod_put(alg);
+               goto out_put_alg;
 
        return tfm;
+
+out_put_alg:
+       crypto_mod_put(alg);
+       return tfm;
 }
 EXPORT_SYMBOL_GPL(crypto_spawn_tfm);
 
@@ -415,6 +425,150 @@ int crypto_unregister_notifier(struct notifier_block *nb)
 }
 EXPORT_SYMBOL_GPL(crypto_unregister_notifier);
 
+struct crypto_attr_type *crypto_get_attr_type(struct rtattr **tb)
+{
+       struct rtattr *rta = tb[CRYPTOA_TYPE - 1];
+       struct crypto_attr_type *algt;
+
+       if (!rta)
+               return ERR_PTR(-ENOENT);
+       if (RTA_PAYLOAD(rta) < sizeof(*algt))
+               return ERR_PTR(-EINVAL);
+
+       algt = RTA_DATA(rta);
+
+       return algt;
+}
+EXPORT_SYMBOL_GPL(crypto_get_attr_type);
+
+int crypto_check_attr_type(struct rtattr **tb, u32 type)
+{
+       struct crypto_attr_type *algt;
+
+       algt = crypto_get_attr_type(tb);
+       if (IS_ERR(algt))
+               return PTR_ERR(algt);
+
+       if ((algt->type ^ type) & algt->mask)
+               return -EINVAL;
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(crypto_check_attr_type);
+
+struct crypto_alg *crypto_get_attr_alg(struct rtattr **tb, u32 type, u32 mask)
+{
+       struct rtattr *rta = tb[CRYPTOA_ALG - 1];
+       struct crypto_attr_alg *alga;
+
+       if (!rta)
+               return ERR_PTR(-ENOENT);
+       if (RTA_PAYLOAD(rta) < sizeof(*alga))
+               return ERR_PTR(-EINVAL);
+
+       alga = RTA_DATA(rta);
+       alga->name[CRYPTO_MAX_ALG_NAME - 1] = 0;
+
+       return crypto_alg_mod_lookup(alga->name, type, mask);
+}
+EXPORT_SYMBOL_GPL(crypto_get_attr_alg);
+
+struct crypto_instance *crypto_alloc_instance(const char *name,
+                                             struct crypto_alg *alg)
+{
+       struct crypto_instance *inst;
+       struct crypto_spawn *spawn;
+       int err;
+
+       inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
+       if (!inst)
+               return ERR_PTR(-ENOMEM);
+
+       err = -ENAMETOOLONG;
+       if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME, "%s(%s)", name,
+                    alg->cra_name) >= CRYPTO_MAX_ALG_NAME)
+               goto err_free_inst;
+
+       if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s(%s)",
+                    name, alg->cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
+               goto err_free_inst;
+
+       spawn = crypto_instance_ctx(inst);
+       err = crypto_init_spawn(spawn, alg, inst);
+
+       if (err)
+               goto err_free_inst;
+
+       return inst;
+
+err_free_inst:
+       kfree(inst);
+       return ERR_PTR(err);
+}
+EXPORT_SYMBOL_GPL(crypto_alloc_instance);
+
+void crypto_init_queue(struct crypto_queue *queue, unsigned int max_qlen)
+{
+       INIT_LIST_HEAD(&queue->list);
+       queue->backlog = &queue->list;
+       queue->qlen = 0;
+       queue->max_qlen = max_qlen;
+}
+EXPORT_SYMBOL_GPL(crypto_init_queue);
+
+int crypto_enqueue_request(struct crypto_queue *queue,
+                          struct crypto_async_request *request)
+{
+       int err = -EINPROGRESS;
+
+       if (unlikely(queue->qlen >= queue->max_qlen)) {
+               err = -EBUSY;
+               if (!(request->flags & CRYPTO_TFM_REQ_MAY_BACKLOG))
+                       goto out;
+               if (queue->backlog == &queue->list)
+                       queue->backlog = &request->list;
+       }
+
+       queue->qlen++;
+       list_add_tail(&request->list, &queue->list);
+
+out:
+       return err;
+}
+EXPORT_SYMBOL_GPL(crypto_enqueue_request);
+
+struct crypto_async_request *crypto_dequeue_request(struct crypto_queue *queue)
+{
+       struct list_head *request;
+
+       if (unlikely(!queue->qlen))
+               return NULL;
+
+       queue->qlen--;
+
+       if (queue->backlog != &queue->list)
+               queue->backlog = queue->backlog->next;
+
+       request = queue->list.next;
+       list_del(request);
+
+       return list_entry(request, struct crypto_async_request, list);
+}
+EXPORT_SYMBOL_GPL(crypto_dequeue_request);
+
+int crypto_tfm_in_queue(struct crypto_queue *queue, struct crypto_tfm *tfm)
+{
+       struct crypto_async_request *req;
+
+       list_for_each_entry(req, &queue->list, list) {
+               if (req->tfm == tfm)
+                       return 1;
+       }
+
+       return 0;
+}
+EXPORT_SYMBOL_GPL(crypto_tfm_in_queue);
+
 static int __init crypto_algapi_init(void)
 {
        crypto_init_proc();