diff options
Diffstat (limited to 'crypto/api.c')
-rw-r--r-- | crypto/api.c | 428 |
1 files changed, 299 insertions, 129 deletions
diff --git a/crypto/api.c b/crypto/api.c index c11ec1fd4f18..2e84d4b54790 100644 --- a/crypto/api.c +++ b/crypto/api.c | |||
@@ -15,70 +15,202 @@ | |||
15 | * | 15 | * |
16 | */ | 16 | */ |
17 | 17 | ||
18 | #include <linux/compiler.h> | 18 | #include <linux/err.h> |
19 | #include <linux/init.h> | ||
20 | #include <linux/crypto.h> | ||
21 | #include <linux/errno.h> | 19 | #include <linux/errno.h> |
22 | #include <linux/kernel.h> | 20 | #include <linux/kernel.h> |
23 | #include <linux/kmod.h> | 21 | #include <linux/kmod.h> |
24 | #include <linux/rwsem.h> | 22 | #include <linux/module.h> |
23 | #include <linux/param.h> | ||
24 | #include <linux/sched.h> | ||
25 | #include <linux/slab.h> | 25 | #include <linux/slab.h> |
26 | #include <linux/string.h> | 26 | #include <linux/string.h> |
27 | #include "internal.h" | 27 | #include "internal.h" |
28 | 28 | ||
29 | LIST_HEAD(crypto_alg_list); | 29 | LIST_HEAD(crypto_alg_list); |
30 | EXPORT_SYMBOL_GPL(crypto_alg_list); | ||
30 | DECLARE_RWSEM(crypto_alg_sem); | 31 | DECLARE_RWSEM(crypto_alg_sem); |
32 | EXPORT_SYMBOL_GPL(crypto_alg_sem); | ||
31 | 33 | ||
32 | static inline int crypto_alg_get(struct crypto_alg *alg) | 34 | BLOCKING_NOTIFIER_HEAD(crypto_chain); |
35 | EXPORT_SYMBOL_GPL(crypto_chain); | ||
36 | |||
37 | static inline struct crypto_alg *crypto_alg_get(struct crypto_alg *alg) | ||
38 | { | ||
39 | atomic_inc(&alg->cra_refcnt); | ||
40 | return alg; | ||
41 | } | ||
42 | |||
43 | struct crypto_alg *crypto_mod_get(struct crypto_alg *alg) | ||
33 | { | 44 | { |
34 | return try_module_get(alg->cra_module); | 45 | return try_module_get(alg->cra_module) ? crypto_alg_get(alg) : NULL; |
35 | } | 46 | } |
47 | EXPORT_SYMBOL_GPL(crypto_mod_get); | ||
36 | 48 | ||
37 | static inline void crypto_alg_put(struct crypto_alg *alg) | 49 | void crypto_mod_put(struct crypto_alg *alg) |
38 | { | 50 | { |
51 | crypto_alg_put(alg); | ||
39 | module_put(alg->cra_module); | 52 | module_put(alg->cra_module); |
40 | } | 53 | } |
54 | EXPORT_SYMBOL_GPL(crypto_mod_put); | ||
41 | 55 | ||
42 | static struct crypto_alg *crypto_alg_lookup(const char *name) | 56 | struct crypto_alg *__crypto_alg_lookup(const char *name, u32 type, u32 mask) |
43 | { | 57 | { |
44 | struct crypto_alg *q, *alg = NULL; | 58 | struct crypto_alg *q, *alg = NULL; |
45 | int best = -1; | 59 | int best = -2; |
46 | 60 | ||
47 | if (!name) | ||
48 | return NULL; | ||
49 | |||
50 | down_read(&crypto_alg_sem); | ||
51 | |||
52 | list_for_each_entry(q, &crypto_alg_list, cra_list) { | 61 | list_for_each_entry(q, &crypto_alg_list, cra_list) { |
53 | int exact, fuzzy; | 62 | int exact, fuzzy; |
54 | 63 | ||
64 | if (crypto_is_moribund(q)) | ||
65 | continue; | ||
66 | |||
67 | if ((q->cra_flags ^ type) & mask) | ||
68 | continue; | ||
69 | |||
70 | if (crypto_is_larval(q) && | ||
71 | ((struct crypto_larval *)q)->mask != mask) | ||
72 | continue; | ||
73 | |||
55 | exact = !strcmp(q->cra_driver_name, name); | 74 | exact = !strcmp(q->cra_driver_name, name); |
56 | fuzzy = !strcmp(q->cra_name, name); | 75 | fuzzy = !strcmp(q->cra_name, name); |
57 | if (!exact && !(fuzzy && q->cra_priority > best)) | 76 | if (!exact && !(fuzzy && q->cra_priority > best)) |
58 | continue; | 77 | continue; |
59 | 78 | ||
60 | if (unlikely(!crypto_alg_get(q))) | 79 | if (unlikely(!crypto_mod_get(q))) |
61 | continue; | 80 | continue; |
62 | 81 | ||
63 | best = q->cra_priority; | 82 | best = q->cra_priority; |
64 | if (alg) | 83 | if (alg) |
65 | crypto_alg_put(alg); | 84 | crypto_mod_put(alg); |
66 | alg = q; | 85 | alg = q; |
67 | 86 | ||
68 | if (exact) | 87 | if (exact) |
69 | break; | 88 | break; |
70 | } | 89 | } |
71 | 90 | ||
91 | return alg; | ||
92 | } | ||
93 | EXPORT_SYMBOL_GPL(__crypto_alg_lookup); | ||
94 | |||
95 | static void crypto_larval_destroy(struct crypto_alg *alg) | ||
96 | { | ||
97 | struct crypto_larval *larval = (void *)alg; | ||
98 | |||
99 | BUG_ON(!crypto_is_larval(alg)); | ||
100 | if (larval->adult) | ||
101 | crypto_mod_put(larval->adult); | ||
102 | kfree(larval); | ||
103 | } | ||
104 | |||
105 | static struct crypto_alg *crypto_larval_alloc(const char *name, u32 type, | ||
106 | u32 mask) | ||
107 | { | ||
108 | struct crypto_alg *alg; | ||
109 | struct crypto_larval *larval; | ||
110 | |||
111 | larval = kzalloc(sizeof(*larval), GFP_KERNEL); | ||
112 | if (!larval) | ||
113 | return ERR_PTR(-ENOMEM); | ||
114 | |||
115 | larval->mask = mask; | ||
116 | larval->alg.cra_flags = CRYPTO_ALG_LARVAL | type; | ||
117 | larval->alg.cra_priority = -1; | ||
118 | larval->alg.cra_destroy = crypto_larval_destroy; | ||
119 | |||
120 | atomic_set(&larval->alg.cra_refcnt, 2); | ||
121 | strlcpy(larval->alg.cra_name, name, CRYPTO_MAX_ALG_NAME); | ||
122 | init_completion(&larval->completion); | ||
123 | |||
124 | down_write(&crypto_alg_sem); | ||
125 | alg = __crypto_alg_lookup(name, type, mask); | ||
126 | if (!alg) { | ||
127 | alg = &larval->alg; | ||
128 | list_add(&alg->cra_list, &crypto_alg_list); | ||
129 | } | ||
130 | up_write(&crypto_alg_sem); | ||
131 | |||
132 | if (alg != &larval->alg) | ||
133 | kfree(larval); | ||
134 | |||
135 | return alg; | ||
136 | } | ||
137 | |||
138 | static void crypto_larval_kill(struct crypto_alg *alg) | ||
139 | { | ||
140 | struct crypto_larval *larval = (void *)alg; | ||
141 | |||
142 | down_write(&crypto_alg_sem); | ||
143 | list_del(&alg->cra_list); | ||
144 | up_write(&crypto_alg_sem); | ||
145 | complete(&larval->completion); | ||
146 | crypto_alg_put(alg); | ||
147 | } | ||
148 | |||
149 | static struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg) | ||
150 | { | ||
151 | struct crypto_larval *larval = (void *)alg; | ||
152 | |||
153 | wait_for_completion_interruptible_timeout(&larval->completion, 60 * HZ); | ||
154 | alg = larval->adult; | ||
155 | if (alg) { | ||
156 | if (!crypto_mod_get(alg)) | ||
157 | alg = ERR_PTR(-EAGAIN); | ||
158 | } else | ||
159 | alg = ERR_PTR(-ENOENT); | ||
160 | crypto_mod_put(&larval->alg); | ||
161 | |||
162 | return alg; | ||
163 | } | ||
164 | |||
165 | static struct crypto_alg *crypto_alg_lookup(const char *name, u32 type, | ||
166 | u32 mask) | ||
167 | { | ||
168 | struct crypto_alg *alg; | ||
169 | |||
170 | down_read(&crypto_alg_sem); | ||
171 | alg = __crypto_alg_lookup(name, type, mask); | ||
72 | up_read(&crypto_alg_sem); | 172 | up_read(&crypto_alg_sem); |
173 | |||
73 | return alg; | 174 | return alg; |
74 | } | 175 | } |
75 | 176 | ||
76 | /* A far more intelligent version of this is planned. For now, just | 177 | struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask) |
77 | * try an exact match on the name of the algorithm. */ | ||
78 | static inline struct crypto_alg *crypto_alg_mod_lookup(const char *name) | ||
79 | { | 178 | { |
80 | return try_then_request_module(crypto_alg_lookup(name), name); | 179 | struct crypto_alg *alg; |
180 | struct crypto_alg *larval; | ||
181 | int ok; | ||
182 | |||
183 | if (!name) | ||
184 | return ERR_PTR(-ENOENT); | ||
185 | |||
186 | mask &= ~(CRYPTO_ALG_LARVAL | CRYPTO_ALG_DEAD); | ||
187 | type &= mask; | ||
188 | |||
189 | alg = try_then_request_module(crypto_alg_lookup(name, type, mask), | ||
190 | name); | ||
191 | if (alg) | ||
192 | return crypto_is_larval(alg) ? crypto_larval_wait(alg) : alg; | ||
193 | |||
194 | larval = crypto_larval_alloc(name, type, mask); | ||
195 | if (IS_ERR(larval) || !crypto_is_larval(larval)) | ||
196 | return larval; | ||
197 | |||
198 | ok = crypto_notify(CRYPTO_MSG_ALG_REQUEST, larval); | ||
199 | if (ok == NOTIFY_DONE) { | ||
200 | request_module("cryptomgr"); | ||
201 | ok = crypto_notify(CRYPTO_MSG_ALG_REQUEST, larval); | ||
202 | } | ||
203 | |||
204 | if (ok == NOTIFY_STOP) | ||
205 | alg = crypto_larval_wait(larval); | ||
206 | else { | ||
207 | crypto_mod_put(larval); | ||
208 | alg = ERR_PTR(-ENOENT); | ||
209 | } | ||
210 | crypto_larval_kill(larval); | ||
211 | return alg; | ||
81 | } | 212 | } |
213 | EXPORT_SYMBOL_GPL(crypto_alg_mod_lookup); | ||
82 | 214 | ||
83 | static int crypto_init_flags(struct crypto_tfm *tfm, u32 flags) | 215 | static int crypto_init_flags(struct crypto_tfm *tfm, u32 flags) |
84 | { | 216 | { |
@@ -94,17 +226,18 @@ static int crypto_init_flags(struct crypto_tfm *tfm, u32 flags) | |||
94 | 226 | ||
95 | case CRYPTO_ALG_TYPE_COMPRESS: | 227 | case CRYPTO_ALG_TYPE_COMPRESS: |
96 | return crypto_init_compress_flags(tfm, flags); | 228 | return crypto_init_compress_flags(tfm, flags); |
97 | |||
98 | default: | ||
99 | break; | ||
100 | } | 229 | } |
101 | 230 | ||
102 | BUG(); | 231 | return 0; |
103 | return -EINVAL; | ||
104 | } | 232 | } |
105 | 233 | ||
106 | static int crypto_init_ops(struct crypto_tfm *tfm) | 234 | static int crypto_init_ops(struct crypto_tfm *tfm) |
107 | { | 235 | { |
236 | const struct crypto_type *type = tfm->__crt_alg->cra_type; | ||
237 | |||
238 | if (type) | ||
239 | return type->init(tfm); | ||
240 | |||
108 | switch (crypto_tfm_alg_type(tfm)) { | 241 | switch (crypto_tfm_alg_type(tfm)) { |
109 | case CRYPTO_ALG_TYPE_CIPHER: | 242 | case CRYPTO_ALG_TYPE_CIPHER: |
110 | return crypto_init_cipher_ops(tfm); | 243 | return crypto_init_cipher_ops(tfm); |
@@ -125,6 +258,14 @@ static int crypto_init_ops(struct crypto_tfm *tfm) | |||
125 | 258 | ||
126 | static void crypto_exit_ops(struct crypto_tfm *tfm) | 259 | static void crypto_exit_ops(struct crypto_tfm *tfm) |
127 | { | 260 | { |
261 | const struct crypto_type *type = tfm->__crt_alg->cra_type; | ||
262 | |||
263 | if (type) { | ||
264 | if (type->exit) | ||
265 | type->exit(tfm); | ||
266 | return; | ||
267 | } | ||
268 | |||
128 | switch (crypto_tfm_alg_type(tfm)) { | 269 | switch (crypto_tfm_alg_type(tfm)) { |
129 | case CRYPTO_ALG_TYPE_CIPHER: | 270 | case CRYPTO_ALG_TYPE_CIPHER: |
130 | crypto_exit_cipher_ops(tfm); | 271 | crypto_exit_cipher_ops(tfm); |
@@ -146,53 +287,67 @@ static void crypto_exit_ops(struct crypto_tfm *tfm) | |||
146 | 287 | ||
147 | static unsigned int crypto_ctxsize(struct crypto_alg *alg, int flags) | 288 | static unsigned int crypto_ctxsize(struct crypto_alg *alg, int flags) |
148 | { | 289 | { |
290 | const struct crypto_type *type = alg->cra_type; | ||
149 | unsigned int len; | 291 | unsigned int len; |
150 | 292 | ||
293 | len = alg->cra_alignmask & ~(crypto_tfm_ctx_alignment() - 1); | ||
294 | if (type) | ||
295 | return len + type->ctxsize(alg); | ||
296 | |||
151 | switch (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) { | 297 | switch (alg->cra_flags & CRYPTO_ALG_TYPE_MASK) { |
152 | default: | 298 | default: |
153 | BUG(); | 299 | BUG(); |
154 | 300 | ||
155 | case CRYPTO_ALG_TYPE_CIPHER: | 301 | case CRYPTO_ALG_TYPE_CIPHER: |
156 | len = crypto_cipher_ctxsize(alg, flags); | 302 | len += crypto_cipher_ctxsize(alg, flags); |
157 | break; | 303 | break; |
158 | 304 | ||
159 | case CRYPTO_ALG_TYPE_DIGEST: | 305 | case CRYPTO_ALG_TYPE_DIGEST: |
160 | len = crypto_digest_ctxsize(alg, flags); | 306 | len += crypto_digest_ctxsize(alg, flags); |
161 | break; | 307 | break; |
162 | 308 | ||
163 | case CRYPTO_ALG_TYPE_COMPRESS: | 309 | case CRYPTO_ALG_TYPE_COMPRESS: |
164 | len = crypto_compress_ctxsize(alg, flags); | 310 | len += crypto_compress_ctxsize(alg, flags); |
165 | break; | 311 | break; |
166 | } | 312 | } |
167 | 313 | ||
168 | return len + (alg->cra_alignmask & ~(crypto_tfm_ctx_alignment() - 1)); | 314 | return len; |
169 | } | 315 | } |
170 | 316 | ||
171 | struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags) | 317 | void crypto_shoot_alg(struct crypto_alg *alg) |
318 | { | ||
319 | down_write(&crypto_alg_sem); | ||
320 | alg->cra_flags |= CRYPTO_ALG_DYING; | ||
321 | up_write(&crypto_alg_sem); | ||
322 | } | ||
323 | EXPORT_SYMBOL_GPL(crypto_shoot_alg); | ||
324 | |||
325 | struct crypto_tfm *__crypto_alloc_tfm(struct crypto_alg *alg, u32 flags) | ||
172 | { | 326 | { |
173 | struct crypto_tfm *tfm = NULL; | 327 | struct crypto_tfm *tfm = NULL; |
174 | struct crypto_alg *alg; | ||
175 | unsigned int tfm_size; | 328 | unsigned int tfm_size; |
176 | 329 | int err = -ENOMEM; | |
177 | alg = crypto_alg_mod_lookup(name); | ||
178 | if (alg == NULL) | ||
179 | goto out; | ||
180 | 330 | ||
181 | tfm_size = sizeof(*tfm) + crypto_ctxsize(alg, flags); | 331 | tfm_size = sizeof(*tfm) + crypto_ctxsize(alg, flags); |
182 | tfm = kzalloc(tfm_size, GFP_KERNEL); | 332 | tfm = kzalloc(tfm_size, GFP_KERNEL); |
183 | if (tfm == NULL) | 333 | if (tfm == NULL) |
184 | goto out_put; | 334 | goto out; |
185 | 335 | ||
186 | tfm->__crt_alg = alg; | 336 | tfm->__crt_alg = alg; |
187 | 337 | ||
188 | if (crypto_init_flags(tfm, flags)) | 338 | err = crypto_init_flags(tfm, flags); |
339 | if (err) | ||
189 | goto out_free_tfm; | 340 | goto out_free_tfm; |
190 | 341 | ||
191 | if (crypto_init_ops(tfm)) | 342 | err = crypto_init_ops(tfm); |
343 | if (err) | ||
192 | goto out_free_tfm; | 344 | goto out_free_tfm; |
193 | 345 | ||
194 | if (alg->cra_init && alg->cra_init(tfm)) | 346 | if (alg->cra_init && (err = alg->cra_init(tfm))) { |
347 | if (err == -EAGAIN) | ||
348 | crypto_shoot_alg(alg); | ||
195 | goto cra_init_failed; | 349 | goto cra_init_failed; |
350 | } | ||
196 | 351 | ||
197 | goto out; | 352 | goto out; |
198 | 353 | ||
@@ -200,13 +355,97 @@ cra_init_failed: | |||
200 | crypto_exit_ops(tfm); | 355 | crypto_exit_ops(tfm); |
201 | out_free_tfm: | 356 | out_free_tfm: |
202 | kfree(tfm); | 357 | kfree(tfm); |
203 | tfm = NULL; | 358 | tfm = ERR_PTR(err); |
204 | out_put: | ||
205 | crypto_alg_put(alg); | ||
206 | out: | 359 | out: |
207 | return tfm; | 360 | return tfm; |
208 | } | 361 | } |
362 | EXPORT_SYMBOL_GPL(__crypto_alloc_tfm); | ||
363 | |||
364 | struct crypto_tfm *crypto_alloc_tfm(const char *name, u32 flags) | ||
365 | { | ||
366 | struct crypto_tfm *tfm = NULL; | ||
367 | int err; | ||
368 | |||
369 | do { | ||
370 | struct crypto_alg *alg; | ||
371 | |||
372 | alg = crypto_alg_mod_lookup(name, 0, CRYPTO_ALG_ASYNC); | ||
373 | err = PTR_ERR(alg); | ||
374 | if (IS_ERR(alg)) | ||
375 | continue; | ||
376 | |||
377 | tfm = __crypto_alloc_tfm(alg, flags); | ||
378 | err = 0; | ||
379 | if (IS_ERR(tfm)) { | ||
380 | crypto_mod_put(alg); | ||
381 | err = PTR_ERR(tfm); | ||
382 | tfm = NULL; | ||
383 | } | ||
384 | } while (err == -EAGAIN && !signal_pending(current)); | ||
385 | |||
386 | return tfm; | ||
387 | } | ||
388 | |||
389 | /* | ||
390 | * crypto_alloc_base - Locate algorithm and allocate transform | ||
391 | * @alg_name: Name of algorithm | ||
392 | * @type: Type of algorithm | ||
393 | * @mask: Mask for type comparison | ||
394 | * | ||
395 | * crypto_alloc_base() will first attempt to locate an already loaded | ||
396 | * algorithm. If that fails and the kernel supports dynamically loadable | ||
397 | * modules, it will then attempt to load a module of the same name or | ||
398 | * alias. If that fails it will send a query to any loaded crypto manager | ||
399 | * to construct an algorithm on the fly. A refcount is grabbed on the | ||
400 | * algorithm which is then associated with the new transform. | ||
401 | * | ||
402 | * The returned transform is of a non-determinate type. Most people | ||
403 | * should use one of the more specific allocation functions such as | ||
404 | * crypto_alloc_blkcipher. | ||
405 | * | ||
406 | * In case of error the return value is an error pointer. | ||
407 | */ | ||
408 | struct crypto_tfm *crypto_alloc_base(const char *alg_name, u32 type, u32 mask) | ||
409 | { | ||
410 | struct crypto_tfm *tfm; | ||
411 | int err; | ||
412 | |||
413 | for (;;) { | ||
414 | struct crypto_alg *alg; | ||
415 | |||
416 | alg = crypto_alg_mod_lookup(alg_name, type, mask); | ||
417 | err = PTR_ERR(alg); | ||
418 | tfm = ERR_PTR(err); | ||
419 | if (IS_ERR(alg)) | ||
420 | goto err; | ||
421 | |||
422 | tfm = __crypto_alloc_tfm(alg, 0); | ||
423 | if (!IS_ERR(tfm)) | ||
424 | break; | ||
425 | |||
426 | crypto_mod_put(alg); | ||
427 | err = PTR_ERR(tfm); | ||
209 | 428 | ||
429 | err: | ||
430 | if (err != -EAGAIN) | ||
431 | break; | ||
432 | if (signal_pending(current)) { | ||
433 | err = -EINTR; | ||
434 | break; | ||
435 | } | ||
436 | }; | ||
437 | |||
438 | return tfm; | ||
439 | } | ||
440 | EXPORT_SYMBOL_GPL(crypto_alloc_base); | ||
441 | |||
442 | /* | ||
443 | * crypto_free_tfm - Free crypto transform | ||
444 | * @tfm: Transform to free | ||
445 | * | ||
446 | * crypto_free_tfm() frees up the transform and any associated resources, | ||
447 | * then drops the refcount on the associated algorithm. | ||
448 | */ | ||
210 | void crypto_free_tfm(struct crypto_tfm *tfm) | 449 | void crypto_free_tfm(struct crypto_tfm *tfm) |
211 | { | 450 | { |
212 | struct crypto_alg *alg; | 451 | struct crypto_alg *alg; |
@@ -221,108 +460,39 @@ void crypto_free_tfm(struct crypto_tfm *tfm) | |||
221 | if (alg->cra_exit) | 460 | if (alg->cra_exit) |
222 | alg->cra_exit(tfm); | 461 | alg->cra_exit(tfm); |
223 | crypto_exit_ops(tfm); | 462 | crypto_exit_ops(tfm); |
224 | crypto_alg_put(alg); | 463 | crypto_mod_put(alg); |
225 | memset(tfm, 0, size); | 464 | memset(tfm, 0, size); |
226 | kfree(tfm); | 465 | kfree(tfm); |
227 | } | 466 | } |
228 | 467 | ||
229 | static inline int crypto_set_driver_name(struct crypto_alg *alg) | 468 | int crypto_alg_available(const char *name, u32 flags) |
230 | { | ||
231 | static const char suffix[] = "-generic"; | ||
232 | char *driver_name = alg->cra_driver_name; | ||
233 | int len; | ||
234 | |||
235 | if (*driver_name) | ||
236 | return 0; | ||
237 | |||
238 | len = strlcpy(driver_name, alg->cra_name, CRYPTO_MAX_ALG_NAME); | ||
239 | if (len + sizeof(suffix) > CRYPTO_MAX_ALG_NAME) | ||
240 | return -ENAMETOOLONG; | ||
241 | |||
242 | memcpy(driver_name + len, suffix, sizeof(suffix)); | ||
243 | return 0; | ||
244 | } | ||
245 | |||
246 | int crypto_register_alg(struct crypto_alg *alg) | ||
247 | { | 469 | { |
248 | int ret; | 470 | int ret = 0; |
249 | struct crypto_alg *q; | 471 | struct crypto_alg *alg = crypto_alg_mod_lookup(name, 0, |
250 | 472 | CRYPTO_ALG_ASYNC); | |
251 | if (alg->cra_alignmask & (alg->cra_alignmask + 1)) | ||
252 | return -EINVAL; | ||
253 | |||
254 | if (alg->cra_alignmask & alg->cra_blocksize) | ||
255 | return -EINVAL; | ||
256 | |||
257 | if (alg->cra_blocksize > PAGE_SIZE / 8) | ||
258 | return -EINVAL; | ||
259 | |||
260 | if (alg->cra_priority < 0) | ||
261 | return -EINVAL; | ||
262 | |||
263 | ret = crypto_set_driver_name(alg); | ||
264 | if (unlikely(ret)) | ||
265 | return ret; | ||
266 | |||
267 | down_write(&crypto_alg_sem); | ||
268 | 473 | ||
269 | list_for_each_entry(q, &crypto_alg_list, cra_list) { | 474 | if (!IS_ERR(alg)) { |
270 | if (q == alg) { | 475 | crypto_mod_put(alg); |
271 | ret = -EEXIST; | 476 | ret = 1; |
272 | goto out; | ||
273 | } | ||
274 | } | 477 | } |
275 | 478 | ||
276 | list_add(&alg->cra_list, &crypto_alg_list); | ||
277 | out: | ||
278 | up_write(&crypto_alg_sem); | ||
279 | return ret; | 479 | return ret; |
280 | } | 480 | } |
281 | 481 | ||
282 | int crypto_unregister_alg(struct crypto_alg *alg) | 482 | EXPORT_SYMBOL_GPL(crypto_alloc_tfm); |
283 | { | 483 | EXPORT_SYMBOL_GPL(crypto_free_tfm); |
284 | int ret = -ENOENT; | 484 | EXPORT_SYMBOL_GPL(crypto_alg_available); |
285 | struct crypto_alg *q; | ||
286 | |||
287 | BUG_ON(!alg->cra_module); | ||
288 | |||
289 | down_write(&crypto_alg_sem); | ||
290 | list_for_each_entry(q, &crypto_alg_list, cra_list) { | ||
291 | if (alg == q) { | ||
292 | list_del(&alg->cra_list); | ||
293 | ret = 0; | ||
294 | goto out; | ||
295 | } | ||
296 | } | ||
297 | out: | ||
298 | up_write(&crypto_alg_sem); | ||
299 | return ret; | ||
300 | } | ||
301 | 485 | ||
302 | int crypto_alg_available(const char *name, u32 flags) | 486 | int crypto_has_alg(const char *name, u32 type, u32 mask) |
303 | { | 487 | { |
304 | int ret = 0; | 488 | int ret = 0; |
305 | struct crypto_alg *alg = crypto_alg_mod_lookup(name); | 489 | struct crypto_alg *alg = crypto_alg_mod_lookup(name, type, mask); |
306 | 490 | ||
307 | if (alg) { | 491 | if (!IS_ERR(alg)) { |
308 | crypto_alg_put(alg); | 492 | crypto_mod_put(alg); |
309 | ret = 1; | 493 | ret = 1; |
310 | } | 494 | } |
311 | 495 | ||
312 | return ret; | 496 | return ret; |
313 | } | 497 | } |
314 | 498 | EXPORT_SYMBOL_GPL(crypto_has_alg); | |
315 | static int __init init_crypto(void) | ||
316 | { | ||
317 | printk(KERN_INFO "Initializing Cryptographic API\n"); | ||
318 | crypto_init_proc(); | ||
319 | return 0; | ||
320 | } | ||
321 | |||
322 | __initcall(init_crypto); | ||
323 | |||
324 | EXPORT_SYMBOL_GPL(crypto_register_alg); | ||
325 | EXPORT_SYMBOL_GPL(crypto_unregister_alg); | ||
326 | EXPORT_SYMBOL_GPL(crypto_alloc_tfm); | ||
327 | EXPORT_SYMBOL_GPL(crypto_free_tfm); | ||
328 | EXPORT_SYMBOL_GPL(crypto_alg_available); | ||