algapi.c (c51b6c8102a82239163c8c04e404c7cc2857b4be) algapi.c (73d3864a4823abda19ebc4387b6ddcbf416e3a77)
1/*
2 * Cryptographic API for algorithms (i.e., low-level API).
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)

--- 7 unchanged lines hidden (view full) ---

16#include <linux/kernel.h>
17#include <linux/list.h>
18#include <linux/module.h>
19#include <linux/rtnetlink.h>
20#include <linux/string.h>
21
22#include "internal.h"
23
1/*
2 * Cryptographic API for algorithms (i.e., low-level API).
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)

--- 7 unchanged lines hidden (view full) ---

16#include <linux/kernel.h>
17#include <linux/list.h>
18#include <linux/module.h>
19#include <linux/rtnetlink.h>
20#include <linux/string.h>
21
22#include "internal.h"
23
24static void crypto_remove_final(struct list_head *list);
25
24static LIST_HEAD(crypto_template_list);
25
26void crypto_larval_error(const char *name, u32 type, u32 mask)
27{
28 struct crypto_alg *alg;
29
30 alg = crypto_alg_lookup(name, type, mask);
31

--- 89 unchanged lines hidden (view full) ---

121 }
122
123 while (!list_empty(&secondary_spawns)) {
124 list_for_each_entry_safe(spawn, n, &secondary_spawns, list)
125 crypto_remove_spawn(spawn, list, &secondary_spawns);
126 }
127}
128
26static LIST_HEAD(crypto_template_list);
27
28void crypto_larval_error(const char *name, u32 type, u32 mask)
29{
30 struct crypto_alg *alg;
31
32 alg = crypto_alg_lookup(name, type, mask);
33

--- 89 unchanged lines hidden (view full) ---

123 }
124
125 while (!list_empty(&secondary_spawns)) {
126 list_for_each_entry_safe(spawn, n, &secondary_spawns, list)
127 crypto_remove_spawn(spawn, list, &secondary_spawns);
128 }
129}
130
129static int __crypto_register_alg(struct crypto_alg *alg,
130 struct list_head *list)
131static struct crypto_larval *__crypto_register_alg(struct crypto_alg *alg)
131{
132 struct crypto_alg *q;
132{
133 struct crypto_alg *q;
134 struct crypto_larval *larval;
133 int ret = -EAGAIN;
134
135 if (crypto_is_dead(alg))
135 int ret = -EAGAIN;
136
137 if (crypto_is_dead(alg))
136 goto out;
138 goto err;
137
138 INIT_LIST_HEAD(&alg->cra_users);
139
139
140 INIT_LIST_HEAD(&alg->cra_users);
141
142 /* No cheating! */
143 alg->cra_flags &= ~CRYPTO_ALG_TESTED;
144
140 ret = -EEXIST;
141
142 atomic_set(&alg->cra_refcnt, 1);
143 list_for_each_entry(q, &crypto_alg_list, cra_list) {
144 if (q == alg)
145 ret = -EEXIST;
146
147 atomic_set(&alg->cra_refcnt, 1);
148 list_for_each_entry(q, &crypto_alg_list, cra_list) {
149 if (q == alg)
145 goto out;
150 goto err;
146
151
152 if (crypto_is_larval(q)) {
153 if (!strcmp(alg->cra_driver_name, q->cra_driver_name))
154 goto err;
155 continue;
156 }
157
158 if (!strcmp(q->cra_driver_name, alg->cra_name) ||
159 !strcmp(q->cra_name, alg->cra_driver_name))
160 goto err;
161 }
162
163 larval = crypto_larval_alloc(alg->cra_name,
164 alg->cra_flags | CRYPTO_ALG_TESTED, 0);
165 if (IS_ERR(larval))
166 goto out;
167
168 ret = -ENOENT;
169 larval->adult = crypto_mod_get(alg);
170 if (!larval->adult)
171 goto free_larval;
172
173 atomic_set(&larval->alg.cra_refcnt, 1);
174 memcpy(larval->alg.cra_driver_name, alg->cra_driver_name,
175 CRYPTO_MAX_ALG_NAME);
176 larval->alg.cra_priority = alg->cra_priority;
177
178 list_add(&alg->cra_list, &crypto_alg_list);
179 list_add(&larval->alg.cra_list, &crypto_alg_list);
180
181out:
182 return larval;
183
184free_larval:
185 kfree(larval);
186err:
187 larval = ERR_PTR(ret);
188 goto out;
189}
190
191void crypto_alg_tested(const char *name, int err)
192{
193 struct crypto_larval *test;
194 struct crypto_alg *alg;
195 struct crypto_alg *q;
196 LIST_HEAD(list);
197
198 down_write(&crypto_alg_sem);
199 list_for_each_entry(q, &crypto_alg_list, cra_list) {
200 if (!crypto_is_larval(q))
201 continue;
202
203 test = (struct crypto_larval *)q;
204
205 if (!strcmp(q->cra_driver_name, name))
206 goto found;
207 }
208
209 printk(KERN_ERR "alg: Unexpected test result for %s: %d\n", name, err);
210 goto unlock;
211
212found:
213 alg = test->adult;
214 if (err || list_empty(&alg->cra_list))
215 goto complete;
216
217 alg->cra_flags |= CRYPTO_ALG_TESTED;
218
219 list_for_each_entry(q, &crypto_alg_list, cra_list) {
220 if (q == alg)
221 continue;
222
147 if (crypto_is_moribund(q))
148 continue;
149
150 if (crypto_is_larval(q)) {
151 struct crypto_larval *larval = (void *)q;
152
153 /*
154 * Check to see if either our generic name or

--- 18 unchanged lines hidden (view full) ---

173
174 if (strcmp(alg->cra_name, q->cra_name))
175 continue;
176
177 if (strcmp(alg->cra_driver_name, q->cra_driver_name) &&
178 q->cra_priority > alg->cra_priority)
179 continue;
180
223 if (crypto_is_moribund(q))
224 continue;
225
226 if (crypto_is_larval(q)) {
227 struct crypto_larval *larval = (void *)q;
228
229 /*
230 * Check to see if either our generic name or

--- 18 unchanged lines hidden (view full) ---

249
250 if (strcmp(alg->cra_name, q->cra_name))
251 continue;
252
253 if (strcmp(alg->cra_driver_name, q->cra_driver_name) &&
254 q->cra_priority > alg->cra_priority)
255 continue;
256
181 crypto_remove_spawns(&q->cra_users, list, alg->cra_flags);
257 crypto_remove_spawns(&q->cra_users, &list, alg->cra_flags);
182 }
258 }
183
184 list_add(&alg->cra_list, &crypto_alg_list);
185
259
186 crypto_notify(CRYPTO_MSG_ALG_REGISTER, alg);
187 ret = 0;
260complete:
261 complete_all(&test->completion);
188
262
189out:
190 return ret;
263unlock:
264 up_write(&crypto_alg_sem);
265
266 crypto_remove_final(&list);
191}
267}
268EXPORT_SYMBOL_GPL(crypto_alg_tested);
192
193static void crypto_remove_final(struct list_head *list)
194{
195 struct crypto_alg *alg;
196 struct crypto_alg *n;
197
198 list_for_each_entry_safe(alg, n, list, cra_list) {
199 list_del_init(&alg->cra_list);
200 crypto_alg_put(alg);
201 }
202}
203
269
270static void crypto_remove_final(struct list_head *list)
271{
272 struct crypto_alg *alg;
273 struct crypto_alg *n;
274
275 list_for_each_entry_safe(alg, n, list, cra_list) {
276 list_del_init(&alg->cra_list);
277 crypto_alg_put(alg);
278 }
279}
280
281static void crypto_wait_for_test(struct crypto_larval *larval)
282{
283 int err;
284
285 err = crypto_probing_notify(CRYPTO_MSG_ALG_REGISTER, larval->adult);
286 if (err != NOTIFY_STOP) {
287 if (WARN_ON(err != NOTIFY_DONE))
288 goto out;
289 crypto_alg_tested(larval->alg.cra_driver_name, 0);
290 }
291
292 err = wait_for_completion_interruptible(&larval->completion);
293 WARN_ON(err);
294
295out:
296 crypto_larval_kill(&larval->alg);
297}
298
204int crypto_register_alg(struct crypto_alg *alg)
205{
299int crypto_register_alg(struct crypto_alg *alg)
300{
206 LIST_HEAD(list);
301 struct crypto_larval *larval;
207 int err;
208
209 err = crypto_check_alg(alg);
210 if (err)
211 return err;
212
213 down_write(&crypto_alg_sem);
302 int err;
303
304 err = crypto_check_alg(alg);
305 if (err)
306 return err;
307
308 down_write(&crypto_alg_sem);
214 err = __crypto_register_alg(alg, &list);
309 larval = __crypto_register_alg(alg);
215 up_write(&crypto_alg_sem);
216
310 up_write(&crypto_alg_sem);
311
217 crypto_remove_final(&list);
218 return err;
312 if (IS_ERR(larval))
313 return PTR_ERR(larval);
314
315 crypto_wait_for_test(larval);
316 return 0;
219}
220EXPORT_SYMBOL_GPL(crypto_register_alg);
221
222static int crypto_remove_alg(struct crypto_alg *alg, struct list_head *list)
223{
224 if (unlikely(list_empty(&alg->cra_list)))
225 return -ENOENT;
226

--- 101 unchanged lines hidden (view full) ---

328{
329 return try_then_request_module(__crypto_lookup_template(name), name);
330}
331EXPORT_SYMBOL_GPL(crypto_lookup_template);
332
333int crypto_register_instance(struct crypto_template *tmpl,
334 struct crypto_instance *inst)
335{
317}
318EXPORT_SYMBOL_GPL(crypto_register_alg);
319
320static int crypto_remove_alg(struct crypto_alg *alg, struct list_head *list)
321{
322 if (unlikely(list_empty(&alg->cra_list)))
323 return -ENOENT;
324

--- 101 unchanged lines hidden (view full) ---

426{
427 return try_then_request_module(__crypto_lookup_template(name), name);
428}
429EXPORT_SYMBOL_GPL(crypto_lookup_template);
430
431int crypto_register_instance(struct crypto_template *tmpl,
432 struct crypto_instance *inst)
433{
336 LIST_HEAD(list);
337 int err = -EINVAL;
434 struct crypto_larval *larval;
435 int err;
338
339 err = crypto_check_alg(&inst->alg);
340 if (err)
341 goto err;
342
343 inst->alg.cra_module = tmpl->module;
344
345 down_write(&crypto_alg_sem);
346
436
437 err = crypto_check_alg(&inst->alg);
438 if (err)
439 goto err;
440
441 inst->alg.cra_module = tmpl->module;
442
443 down_write(&crypto_alg_sem);
444
347 err = __crypto_register_alg(&inst->alg, &list);
348 if (err)
445 larval = __crypto_register_alg(&inst->alg);
446 if (IS_ERR(larval))
349 goto unlock;
350
351 hlist_add_head(&inst->list, &tmpl->instances);
352 inst->tmpl = tmpl;
353
354unlock:
355 up_write(&crypto_alg_sem);
356
447 goto unlock;
448
449 hlist_add_head(&inst->list, &tmpl->instances);
450 inst->tmpl = tmpl;
451
452unlock:
453 up_write(&crypto_alg_sem);
454
357 crypto_remove_final(&list);
455 err = PTR_ERR(larval);
456 if (IS_ERR(larval))
457 goto err;
358
458
459 crypto_wait_for_test(larval);
460 err = 0;
461
359err:
360 return err;
361}
362EXPORT_SYMBOL_GPL(crypto_register_instance);
363
364int crypto_init_spawn(struct crypto_spawn *spawn, struct crypto_alg *alg,
365 struct crypto_instance *inst, u32 mask)
366{

--- 316 unchanged lines hidden ---
462err:
463 return err;
464}
465EXPORT_SYMBOL_GPL(crypto_register_instance);
466
467int crypto_init_spawn(struct crypto_spawn *spawn, struct crypto_alg *alg,
468 struct crypto_instance *inst, u32 mask)
469{

--- 316 unchanged lines hidden ---