1/*
2 * Create default crypto algorithm instances.
3 *
4 * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au>
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
9 * any later version.
10 *
11 */
12
13#include <linux/crypto.h>
14#include <linux/ctype.h>
15#include <linux/err.h>
16#include <linux/init.h>
17#include <linux/kthread.h>
18#include <linux/module.h>
19#include <linux/notifier.h>
20#include <linux/rtnetlink.h>
21#include <linux/sched.h>
22#include <linux/string.h>
23
24#include "internal.h"
25
26struct cryptomgr_param {
27	struct rtattr *tb[CRYPTOA_MAX];
28
29	struct {
30		struct rtattr attr;
31		struct crypto_attr_type data;
32	} type;
33
34	struct {
35		struct rtattr attr;
36		struct crypto_attr_alg data;
37	} alg;
38
39	struct {
40		char name[CRYPTO_MAX_ALG_NAME];
41	} larval;
42
43	char template[CRYPTO_MAX_ALG_NAME];
44};
45
46static int cryptomgr_probe(void *data)
47{
48	struct cryptomgr_param *param = data;
49	struct crypto_template *tmpl;
50	struct crypto_instance *inst;
51	int err;
52
53	tmpl = crypto_lookup_template(param->template);
54	if (!tmpl)
55		goto err;
56
57	do {
58		inst = tmpl->alloc(param->tb);
59		if (IS_ERR(inst))
60			err = PTR_ERR(inst);
61		else if ((err = crypto_register_instance(tmpl, inst)))
62			tmpl->free(inst);
63	} while (err == -EAGAIN && !signal_pending(current));
64
65	crypto_tmpl_put(tmpl);
66
67	if (err)
68		goto err;
69
70out:
71	kfree(param);
72	module_put_and_exit(0);
73
74err:
75	crypto_larval_error(param->larval.name, param->type.data.type,
76			    param->type.data.mask);
77	goto out;
78}
79
80static int cryptomgr_schedule_probe(struct crypto_larval *larval)
81{
82	struct task_struct *thread;
83	struct cryptomgr_param *param;
84	const char *name = larval->alg.cra_name;
85	const char *p;
86	unsigned int len;
87
88	if (!try_module_get(THIS_MODULE))
89		goto err;
90
91	param = kzalloc(sizeof(*param), GFP_KERNEL);
92	if (!param)
93		goto err_put_module;
94
95	for (p = name; isalnum(*p) || *p == '-' || *p == '_'; p++)
96		;
97
98	len = p - name;
99	if (!len || *p != '(')
100		goto err_free_param;
101
102	memcpy(param->template, name, len);
103
104	name = p + 1;
105	len = 0;
106	for (p = name; *p; p++) {
107		for (; isalnum(*p) || *p == '-' || *p == '_' || *p == '('; p++)
108			;
109
110		if (*p != ')')
111			goto err_free_param;
112
113		len = p - name;
114	}
115
116	if (!len || name[len + 1])
117		goto err_free_param;
118
119	param->type.attr.rta_len = sizeof(param->type);
120	param->type.attr.rta_type = CRYPTOA_TYPE;
121	param->type.data.type = larval->alg.cra_flags;
122	param->type.data.mask = larval->mask;
123	param->tb[CRYPTOA_TYPE - 1] = &param->type.attr;
124
125	param->alg.attr.rta_len = sizeof(param->alg);
126	param->alg.attr.rta_type = CRYPTOA_ALG;
127	memcpy(param->alg.data.name, name, len);
128	param->tb[CRYPTOA_ALG - 1] = &param->alg.attr;
129
130	memcpy(param->larval.name, larval->alg.cra_name, CRYPTO_MAX_ALG_NAME);
131
132	thread = kthread_run(cryptomgr_probe, param, "cryptomgr");
133	if (IS_ERR(thread))
134		goto err_free_param;
135
136	return NOTIFY_STOP;
137
138err_free_param:
139	kfree(param);
140err_put_module:
141	module_put(THIS_MODULE);
142err:
143	return NOTIFY_OK;
144}
145
146static int cryptomgr_notify(struct notifier_block *this, unsigned long msg,
147			    void *data)
148{
149	switch (msg) {
150	case CRYPTO_MSG_ALG_REQUEST:
151		return cryptomgr_schedule_probe(data);
152	}
153
154	return NOTIFY_DONE;
155}
156
157static struct notifier_block cryptomgr_notifier = {
158	.notifier_call = cryptomgr_notify,
159};
160
161static int __init cryptomgr_init(void)
162{
163	return crypto_register_notifier(&cryptomgr_notifier);
164}
165
166static void __exit cryptomgr_exit(void)
167{
168	int err = crypto_unregister_notifier(&cryptomgr_notifier);
169	BUG_ON(err);
170}
171
172module_init(cryptomgr_init);
173module_exit(cryptomgr_exit);
174
175MODULE_LICENSE("GPL");
176MODULE_DESCRIPTION("Crypto Algorithm Manager");
177