aboutsummaryrefslogtreecommitdiffstats
path: root/crypto/algapi.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/algapi.c')
-rw-r--r--crypto/algapi.c169
1 files changed, 137 insertions, 32 deletions
diff --git a/crypto/algapi.c b/crypto/algapi.c
index f7d2185b2c8f..f137a432061f 100644
--- a/crypto/algapi.c
+++ b/crypto/algapi.c
@@ -84,36 +84,47 @@ static void crypto_destroy_instance(struct crypto_alg *alg)
crypto_tmpl_put(tmpl);
}
-static void crypto_remove_spawns(struct list_head *spawns,
- struct list_head *list)
+static void crypto_remove_spawn(struct crypto_spawn *spawn,
+ struct list_head *list,
+ struct list_head *secondary_spawns)
{
- struct crypto_spawn *spawn, *n;
+ struct crypto_instance *inst = spawn->inst;
+ struct crypto_template *tmpl = inst->tmpl;
- list_for_each_entry_safe(spawn, n, spawns, list) {
- struct crypto_instance *inst = spawn->inst;
- struct crypto_template *tmpl = inst->tmpl;
+ list_del_init(&spawn->list);
+ spawn->alg = NULL;
- list_del_init(&spawn->list);
- spawn->alg = NULL;
+ if (crypto_is_dead(&inst->alg))
+ return;
- if (crypto_is_dead(&inst->alg))
- continue;
+ inst->alg.cra_flags |= CRYPTO_ALG_DEAD;
+ if (!tmpl || !crypto_tmpl_get(tmpl))
+ return;
- inst->alg.cra_flags |= CRYPTO_ALG_DEAD;
- if (!tmpl || !crypto_tmpl_get(tmpl))
+ crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, &inst->alg);
+ list_move(&inst->alg.cra_list, list);
+ hlist_del(&inst->list);
+ inst->alg.cra_destroy = crypto_destroy_instance;
+
+ list_splice(&inst->alg.cra_users, secondary_spawns);
+}
+
+static void crypto_remove_spawns(struct list_head *spawns,
+ struct list_head *list, u32 new_type)
+{
+ struct crypto_spawn *spawn, *n;
+ LIST_HEAD(secondary_spawns);
+
+ list_for_each_entry_safe(spawn, n, spawns, list) {
+ if ((spawn->alg->cra_flags ^ new_type) & spawn->mask)
continue;
- crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, &inst->alg);
- list_move(&inst->alg.cra_list, list);
- hlist_del(&inst->list);
- inst->alg.cra_destroy = crypto_destroy_instance;
+ crypto_remove_spawn(spawn, list, &secondary_spawns);
+ }
- if (!list_empty(&inst->alg.cra_users)) {
- if (&n->list == spawns)
- n = list_entry(inst->alg.cra_users.next,
- typeof(*n), list);
- __list_splice(&inst->alg.cra_users, spawns->prev);
- }
+ while (!list_empty(&secondary_spawns)) {
+ list_for_each_entry_safe(spawn, n, &secondary_spawns, list)
+ crypto_remove_spawn(spawn, list, &secondary_spawns);
}
}
@@ -164,7 +175,7 @@ static int __crypto_register_alg(struct crypto_alg *alg,
q->cra_priority > alg->cra_priority)
continue;
- crypto_remove_spawns(&q->cra_users, list);
+ crypto_remove_spawns(&q->cra_users, list, alg->cra_flags);
}
list_add(&alg->cra_list, &crypto_alg_list);
@@ -214,7 +225,7 @@ static int crypto_remove_alg(struct crypto_alg *alg, struct list_head *list)
crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, alg);
list_del_init(&alg->cra_list);
- crypto_remove_spawns(&alg->cra_users, list);
+ crypto_remove_spawns(&alg->cra_users, list, alg->cra_flags);
return 0;
}
@@ -351,11 +362,12 @@ err:
EXPORT_SYMBOL_GPL(crypto_register_instance);
int crypto_init_spawn(struct crypto_spawn *spawn, struct crypto_alg *alg,
- struct crypto_instance *inst)
+ struct crypto_instance *inst, u32 mask)
{
int err = -EAGAIN;
spawn->inst = inst;
+ spawn->mask = mask;
down_write(&crypto_alg_sem);
if (!crypto_is_moribund(alg)) {
@@ -425,15 +437,45 @@ int crypto_unregister_notifier(struct notifier_block *nb)
}
EXPORT_SYMBOL_GPL(crypto_unregister_notifier);
-struct crypto_alg *crypto_get_attr_alg(void *param, unsigned int len,
- u32 type, u32 mask)
+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 rtattr *rta = param;
+ 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_OK(rta, len))
- return ERR_PTR(-EBADR);
- if (rta->rta_type != CRYPTOA_ALG || RTA_PAYLOAD(rta) < sizeof(*alga))
+ if (!rta)
+ return ERR_PTR(-ENOENT);
+ if (RTA_PAYLOAD(rta) < sizeof(*alga))
return ERR_PTR(-EINVAL);
alga = RTA_DATA(rta);
@@ -464,7 +506,8 @@ struct crypto_instance *crypto_alloc_instance(const char *name,
goto err_free_inst;
spawn = crypto_instance_ctx(inst);
- err = crypto_init_spawn(spawn, alg, inst);
+ err = crypto_init_spawn(spawn, alg, inst,
+ CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC);
if (err)
goto err_free_inst;
@@ -477,6 +520,68 @@ err_free_inst:
}
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();