diff options
author | Ingo Molnar <mingo@elte.hu> | 2008-10-12 15:17:14 +0200 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-10-12 15:17:14 +0200 |
commit | 620f2efcdc5c7a2db68da41bc3df3cf9a718024e (patch) | |
tree | b1a0411e2588953777d0b10245b12044c33cef54 /crypto/algboss.c | |
parent | 04944b793e18ece23f63c0252646b310c1845940 (diff) | |
parent | fd048088306656824958e7783ffcee27e241b361 (diff) |
Merge branch 'linus' into x86/xsave
Diffstat (limited to 'crypto/algboss.c')
-rw-r--r-- | crypto/algboss.c | 300 |
1 files changed, 300 insertions, 0 deletions
diff --git a/crypto/algboss.c b/crypto/algboss.c new file mode 100644 index 00000000000..4601e4267c8 --- /dev/null +++ b/crypto/algboss.c @@ -0,0 +1,300 @@ +/* + * Create default crypto algorithm instances. + * + * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au> + * + * This program is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License as published by the Free + * Software Foundation; either version 2 of the License, or (at your option) + * any later version. + * + */ + +#include <linux/crypto.h> +#include <linux/ctype.h> +#include <linux/err.h> +#include <linux/init.h> +#include <linux/kthread.h> +#include <linux/module.h> +#include <linux/notifier.h> +#include <linux/rtnetlink.h> +#include <linux/sched.h> +#include <linux/string.h> + +#include "internal.h" + +struct cryptomgr_param { + struct rtattr *tb[CRYPTO_MAX_ATTRS + 2]; + + struct { + struct rtattr attr; + struct crypto_attr_type data; + } type; + + union { + struct rtattr attr; + struct { + struct rtattr attr; + struct crypto_attr_alg data; + } alg; + struct { + struct rtattr attr; + struct crypto_attr_u32 data; + } nu32; + } attrs[CRYPTO_MAX_ATTRS]; + + char larval[CRYPTO_MAX_ALG_NAME]; + char template[CRYPTO_MAX_ALG_NAME]; + + u32 otype; + u32 omask; +}; + +struct crypto_test_param { + char driver[CRYPTO_MAX_ALG_NAME]; + char alg[CRYPTO_MAX_ALG_NAME]; + u32 type; +}; + +static int cryptomgr_probe(void *data) +{ + struct cryptomgr_param *param = data; + struct crypto_template *tmpl; + struct crypto_instance *inst; + int err; + + tmpl = crypto_lookup_template(param->template); + if (!tmpl) + goto err; + + do { + inst = tmpl->alloc(param->tb); + if (IS_ERR(inst)) + err = PTR_ERR(inst); + else if ((err = crypto_register_instance(tmpl, inst))) + tmpl->free(inst); + } while (err == -EAGAIN && !signal_pending(current)); + + crypto_tmpl_put(tmpl); + + if (err) + goto err; + +out: + kfree(param); + module_put_and_exit(0); + +err: + crypto_larval_error(param->larval, param->otype, param->omask); + goto out; +} + +static int cryptomgr_schedule_probe(struct crypto_larval *larval) +{ + struct task_struct *thread; + struct cryptomgr_param *param; + const char *name = larval->alg.cra_name; + const char *p; + unsigned int len; + int i; + + if (!try_module_get(THIS_MODULE)) + goto err; + + param = kzalloc(sizeof(*param), GFP_KERNEL); + if (!param) + goto err_put_module; + + for (p = name; isalnum(*p) || *p == '-' || *p == '_'; p++) + ; + + len = p - name; + if (!len || *p != '(') + goto err_free_param; + + memcpy(param->template, name, len); + + i = 0; + for (;;) { + int notnum = 0; + + name = ++p; + len = 0; + + for (; isalnum(*p) || *p == '-' || *p == '_'; p++) + notnum |= !isdigit(*p); + + if (*p == '(') { + int recursion = 0; + + for (;;) { + if (!*++p) + goto err_free_param; + if (*p == '(') + recursion++; + else if (*p == ')' && !recursion--) + break; + } + + notnum = 1; + p++; + } + + len = p - name; + if (!len) + goto err_free_param; + + if (notnum) { + param->attrs[i].alg.attr.rta_len = + sizeof(param->attrs[i].alg); + param->attrs[i].alg.attr.rta_type = CRYPTOA_ALG; + memcpy(param->attrs[i].alg.data.name, name, len); + } else { + param->attrs[i].nu32.attr.rta_len = + sizeof(param->attrs[i].nu32); + param->attrs[i].nu32.attr.rta_type = CRYPTOA_U32; + param->attrs[i].nu32.data.num = + simple_strtol(name, NULL, 0); + } + + param->tb[i + 1] = ¶m->attrs[i].attr; + i++; + + if (i >= CRYPTO_MAX_ATTRS) + goto err_free_param; + + if (*p == ')') + break; + + if (*p != ',') + goto err_free_param; + } + + if (!i) + goto err_free_param; + + param->tb[i + 1] = NULL; + + param->type.attr.rta_len = sizeof(param->type); + param->type.attr.rta_type = CRYPTOA_TYPE; + param->type.data.type = larval->alg.cra_flags & ~CRYPTO_ALG_TESTED; + param->type.data.mask = larval->mask & ~CRYPTO_ALG_TESTED; + param->tb[0] = ¶m->type.attr; + + param->otype = larval->alg.cra_flags; + param->omask = larval->mask; + + memcpy(param->larval, larval->alg.cra_name, CRYPTO_MAX_ALG_NAME); + + thread = kthread_run(cryptomgr_probe, param, "cryptomgr_probe"); + if (IS_ERR(thread)) + goto err_free_param; + + return NOTIFY_STOP; + +err_free_param: + kfree(param); +err_put_module: + module_put(THIS_MODULE); +err: + return NOTIFY_OK; +} + +static int cryptomgr_test(void *data) +{ + struct crypto_test_param *param = data; + u32 type = param->type; + int err = 0; + + if (!((type ^ CRYPTO_ALG_TYPE_BLKCIPHER) & + CRYPTO_ALG_TYPE_BLKCIPHER_MASK) && !(type & CRYPTO_ALG_GENIV)) + goto skiptest; + + err = alg_test(param->driver, param->alg, type, CRYPTO_ALG_TESTED); + +skiptest: + crypto_alg_tested(param->driver, err); + + kfree(param); + module_put_and_exit(0); +} + +static int cryptomgr_schedule_test(struct crypto_alg *alg) +{ + struct task_struct *thread; + struct crypto_test_param *param; + + if (!try_module_get(THIS_MODULE)) + goto err; + + param = kzalloc(sizeof(*param), GFP_KERNEL); + if (!param) + goto err_put_module; + + memcpy(param->driver, alg->cra_driver_name, sizeof(param->driver)); + memcpy(param->alg, alg->cra_name, sizeof(param->alg)); + param->type = alg->cra_flags; + + thread = kthread_run(cryptomgr_test, param, "cryptomgr_test"); + if (IS_ERR(thread)) + goto err_free_param; + + return NOTIFY_STOP; + +err_free_param: + kfree(param); +err_put_module: + module_put(THIS_MODULE); +err: + return NOTIFY_OK; +} + +static int cryptomgr_notify(struct notifier_block *this, unsigned long msg, + void *data) +{ + switch (msg) { + case CRYPTO_MSG_ALG_REQUEST: + return cryptomgr_schedule_probe(data); + case CRYPTO_MSG_ALG_REGISTER: + return cryptomgr_schedule_test(data); + } + + return NOTIFY_DONE; +} + +static struct notifier_block cryptomgr_notifier = { + .notifier_call = cryptomgr_notify, +}; + +static int __init cryptomgr_init(void) +{ + int err; + + err = testmgr_init(); + if (err) + return err; + + err = crypto_register_notifier(&cryptomgr_notifier); + if (err) + goto free_testmgr; + + return 0; + +free_testmgr: + testmgr_exit(); + return err; +} + +static void __exit cryptomgr_exit(void) +{ + int err = crypto_unregister_notifier(&cryptomgr_notifier); + BUG_ON(err); + + testmgr_exit(); +} + +subsys_initcall(cryptomgr_init); +module_exit(cryptomgr_exit); + +MODULE_LICENSE("GPL"); +MODULE_DESCRIPTION("Crypto Algorithm Manager"); |