OpenCores
URL https://opencores.org/ocsvn/test_project/test_project/trunk

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [crypto/] [algapi.c] - Blame information for rev 81

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
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)
9
 * any later version.
10
 *
11
 */
12
 
13
#include <linux/err.h>
14
#include <linux/errno.h>
15
#include <linux/init.h>
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
 
24
static LIST_HEAD(crypto_template_list);
25
 
26
void crypto_larval_error(const char *name, u32 type, u32 mask)
27
{
28
        struct crypto_alg *alg;
29
 
30
        down_read(&crypto_alg_sem);
31
        alg = __crypto_alg_lookup(name, type, mask);
32
        up_read(&crypto_alg_sem);
33
 
34
        if (alg) {
35
                if (crypto_is_larval(alg)) {
36
                        struct crypto_larval *larval = (void *)alg;
37
                        complete_all(&larval->completion);
38
                }
39
                crypto_mod_put(alg);
40
        }
41
}
42
EXPORT_SYMBOL_GPL(crypto_larval_error);
43
 
44
static inline int crypto_set_driver_name(struct crypto_alg *alg)
45
{
46
        static const char suffix[] = "-generic";
47
        char *driver_name = alg->cra_driver_name;
48
        int len;
49
 
50
        if (*driver_name)
51
                return 0;
52
 
53
        len = strlcpy(driver_name, alg->cra_name, CRYPTO_MAX_ALG_NAME);
54
        if (len + sizeof(suffix) > CRYPTO_MAX_ALG_NAME)
55
                return -ENAMETOOLONG;
56
 
57
        memcpy(driver_name + len, suffix, sizeof(suffix));
58
        return 0;
59
}
60
 
61
static int crypto_check_alg(struct crypto_alg *alg)
62
{
63
        if (alg->cra_alignmask & (alg->cra_alignmask + 1))
64
                return -EINVAL;
65
 
66
        if (alg->cra_blocksize > PAGE_SIZE / 8)
67
                return -EINVAL;
68
 
69
        if (alg->cra_priority < 0)
70
                return -EINVAL;
71
 
72
        return crypto_set_driver_name(alg);
73
}
74
 
75
static void crypto_destroy_instance(struct crypto_alg *alg)
76
{
77
        struct crypto_instance *inst = (void *)alg;
78
        struct crypto_template *tmpl = inst->tmpl;
79
 
80
        tmpl->free(inst);
81
        crypto_tmpl_put(tmpl);
82
}
83
 
84
static void crypto_remove_spawn(struct crypto_spawn *spawn,
85
                                struct list_head *list,
86
                                struct list_head *secondary_spawns)
87
{
88
        struct crypto_instance *inst = spawn->inst;
89
        struct crypto_template *tmpl = inst->tmpl;
90
 
91
        list_del_init(&spawn->list);
92
        spawn->alg = NULL;
93
 
94
        if (crypto_is_dead(&inst->alg))
95
                return;
96
 
97
        inst->alg.cra_flags |= CRYPTO_ALG_DEAD;
98
        if (hlist_unhashed(&inst->list))
99
                return;
100
 
101
        if (!tmpl || !crypto_tmpl_get(tmpl))
102
                return;
103
 
104
        crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, &inst->alg);
105
        list_move(&inst->alg.cra_list, list);
106
        hlist_del(&inst->list);
107
        inst->alg.cra_destroy = crypto_destroy_instance;
108
 
109
        list_splice(&inst->alg.cra_users, secondary_spawns);
110
}
111
 
112
static void crypto_remove_spawns(struct list_head *spawns,
113
                                 struct list_head *list, u32 new_type)
114
{
115
        struct crypto_spawn *spawn, *n;
116
        LIST_HEAD(secondary_spawns);
117
 
118
        list_for_each_entry_safe(spawn, n, spawns, list) {
119
                if ((spawn->alg->cra_flags ^ new_type) & spawn->mask)
120
                        continue;
121
 
122
                crypto_remove_spawn(spawn, list, &secondary_spawns);
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
 
131
static int __crypto_register_alg(struct crypto_alg *alg,
132
                                 struct list_head *list)
133
{
134
        struct crypto_alg *q;
135
        int ret = -EAGAIN;
136
 
137
        if (crypto_is_dead(alg))
138
                goto out;
139
 
140
        INIT_LIST_HEAD(&alg->cra_users);
141
 
142
        ret = -EEXIST;
143
 
144
        atomic_set(&alg->cra_refcnt, 1);
145
        list_for_each_entry(q, &crypto_alg_list, cra_list) {
146
                if (q == alg)
147
                        goto out;
148
 
149
                if (crypto_is_moribund(q))
150
                        continue;
151
 
152
                if (crypto_is_larval(q)) {
153
                        struct crypto_larval *larval = (void *)q;
154
 
155
                        /*
156
                         * Check to see if either our generic name or
157
                         * specific name can satisfy the name requested
158
                         * by the larval entry q.
159
                         */
160
                        if (strcmp(alg->cra_name, q->cra_name) &&
161
                            strcmp(alg->cra_driver_name, q->cra_name))
162
                                continue;
163
 
164
                        if (larval->adult)
165
                                continue;
166
                        if ((q->cra_flags ^ alg->cra_flags) & larval->mask)
167
                                continue;
168
                        if (!crypto_mod_get(alg))
169
                                continue;
170
 
171
                        larval->adult = alg;
172
                        complete_all(&larval->completion);
173
                        continue;
174
                }
175
 
176
                if (strcmp(alg->cra_name, q->cra_name))
177
                        continue;
178
 
179
                if (strcmp(alg->cra_driver_name, q->cra_driver_name) &&
180
                    q->cra_priority > alg->cra_priority)
181
                        continue;
182
 
183
                crypto_remove_spawns(&q->cra_users, list, alg->cra_flags);
184
        }
185
 
186
        list_add(&alg->cra_list, &crypto_alg_list);
187
 
188
        crypto_notify(CRYPTO_MSG_ALG_REGISTER, alg);
189
        ret = 0;
190
 
191
out:
192
        return ret;
193
}
194
 
195
static void crypto_remove_final(struct list_head *list)
196
{
197
        struct crypto_alg *alg;
198
        struct crypto_alg *n;
199
 
200
        list_for_each_entry_safe(alg, n, list, cra_list) {
201
                list_del_init(&alg->cra_list);
202
                crypto_alg_put(alg);
203
        }
204
}
205
 
206
int crypto_register_alg(struct crypto_alg *alg)
207
{
208
        LIST_HEAD(list);
209
        int err;
210
 
211
        err = crypto_check_alg(alg);
212
        if (err)
213
                return err;
214
 
215
        down_write(&crypto_alg_sem);
216
        err = __crypto_register_alg(alg, &list);
217
        up_write(&crypto_alg_sem);
218
 
219
        crypto_remove_final(&list);
220
        return err;
221
}
222
EXPORT_SYMBOL_GPL(crypto_register_alg);
223
 
224
static int crypto_remove_alg(struct crypto_alg *alg, struct list_head *list)
225
{
226
        if (unlikely(list_empty(&alg->cra_list)))
227
                return -ENOENT;
228
 
229
        alg->cra_flags |= CRYPTO_ALG_DEAD;
230
 
231
        crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, alg);
232
        list_del_init(&alg->cra_list);
233
        crypto_remove_spawns(&alg->cra_users, list, alg->cra_flags);
234
 
235
        return 0;
236
}
237
 
238
int crypto_unregister_alg(struct crypto_alg *alg)
239
{
240
        int ret;
241
        LIST_HEAD(list);
242
 
243
        down_write(&crypto_alg_sem);
244
        ret = crypto_remove_alg(alg, &list);
245
        up_write(&crypto_alg_sem);
246
 
247
        if (ret)
248
                return ret;
249
 
250
        BUG_ON(atomic_read(&alg->cra_refcnt) != 1);
251
        if (alg->cra_destroy)
252
                alg->cra_destroy(alg);
253
 
254
        crypto_remove_final(&list);
255
        return 0;
256
}
257
EXPORT_SYMBOL_GPL(crypto_unregister_alg);
258
 
259
int crypto_register_template(struct crypto_template *tmpl)
260
{
261
        struct crypto_template *q;
262
        int err = -EEXIST;
263
 
264
        down_write(&crypto_alg_sem);
265
 
266
        list_for_each_entry(q, &crypto_template_list, list) {
267
                if (q == tmpl)
268
                        goto out;
269
        }
270
 
271
        list_add(&tmpl->list, &crypto_template_list);
272
        crypto_notify(CRYPTO_MSG_TMPL_REGISTER, tmpl);
273
        err = 0;
274
out:
275
        up_write(&crypto_alg_sem);
276
        return err;
277
}
278
EXPORT_SYMBOL_GPL(crypto_register_template);
279
 
280
void crypto_unregister_template(struct crypto_template *tmpl)
281
{
282
        struct crypto_instance *inst;
283
        struct hlist_node *p, *n;
284
        struct hlist_head *list;
285
        LIST_HEAD(users);
286
 
287
        down_write(&crypto_alg_sem);
288
 
289
        BUG_ON(list_empty(&tmpl->list));
290
        list_del_init(&tmpl->list);
291
 
292
        list = &tmpl->instances;
293
        hlist_for_each_entry(inst, p, list, list) {
294
                int err = crypto_remove_alg(&inst->alg, &users);
295
                BUG_ON(err);
296
        }
297
 
298
        crypto_notify(CRYPTO_MSG_TMPL_UNREGISTER, tmpl);
299
 
300
        up_write(&crypto_alg_sem);
301
 
302
        hlist_for_each_entry_safe(inst, p, n, list, list) {
303
                BUG_ON(atomic_read(&inst->alg.cra_refcnt) != 1);
304
                tmpl->free(inst);
305
        }
306
        crypto_remove_final(&users);
307
}
308
EXPORT_SYMBOL_GPL(crypto_unregister_template);
309
 
310
static struct crypto_template *__crypto_lookup_template(const char *name)
311
{
312
        struct crypto_template *q, *tmpl = NULL;
313
 
314
        down_read(&crypto_alg_sem);
315
        list_for_each_entry(q, &crypto_template_list, list) {
316
                if (strcmp(q->name, name))
317
                        continue;
318
                if (unlikely(!crypto_tmpl_get(q)))
319
                        continue;
320
 
321
                tmpl = q;
322
                break;
323
        }
324
        up_read(&crypto_alg_sem);
325
 
326
        return tmpl;
327
}
328
 
329
struct crypto_template *crypto_lookup_template(const char *name)
330
{
331
        return try_then_request_module(__crypto_lookup_template(name), name);
332
}
333
EXPORT_SYMBOL_GPL(crypto_lookup_template);
334
 
335
int crypto_register_instance(struct crypto_template *tmpl,
336
                             struct crypto_instance *inst)
337
{
338
        LIST_HEAD(list);
339
        int err = -EINVAL;
340
 
341
        err = crypto_check_alg(&inst->alg);
342
        if (err)
343
                goto err;
344
 
345
        inst->alg.cra_module = tmpl->module;
346
 
347
        down_write(&crypto_alg_sem);
348
 
349
        err = __crypto_register_alg(&inst->alg, &list);
350
        if (err)
351
                goto unlock;
352
 
353
        hlist_add_head(&inst->list, &tmpl->instances);
354
        inst->tmpl = tmpl;
355
 
356
unlock:
357
        up_write(&crypto_alg_sem);
358
 
359
        crypto_remove_final(&list);
360
 
361
err:
362
        return err;
363
}
364
EXPORT_SYMBOL_GPL(crypto_register_instance);
365
 
366
int crypto_init_spawn(struct crypto_spawn *spawn, struct crypto_alg *alg,
367
                      struct crypto_instance *inst, u32 mask)
368
{
369
        int err = -EAGAIN;
370
 
371
        spawn->inst = inst;
372
        spawn->mask = mask;
373
 
374
        down_write(&crypto_alg_sem);
375
        if (!crypto_is_moribund(alg)) {
376
                list_add(&spawn->list, &alg->cra_users);
377
                spawn->alg = alg;
378
                err = 0;
379
        }
380
        up_write(&crypto_alg_sem);
381
 
382
        return err;
383
}
384
EXPORT_SYMBOL_GPL(crypto_init_spawn);
385
 
386
void crypto_drop_spawn(struct crypto_spawn *spawn)
387
{
388
        down_write(&crypto_alg_sem);
389
        list_del(&spawn->list);
390
        up_write(&crypto_alg_sem);
391
}
392
EXPORT_SYMBOL_GPL(crypto_drop_spawn);
393
 
394
struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn, u32 type,
395
                                    u32 mask)
396
{
397
        struct crypto_alg *alg;
398
        struct crypto_alg *alg2;
399
        struct crypto_tfm *tfm;
400
 
401
        down_read(&crypto_alg_sem);
402
        alg = spawn->alg;
403
        alg2 = alg;
404
        if (alg2)
405
                alg2 = crypto_mod_get(alg2);
406
        up_read(&crypto_alg_sem);
407
 
408
        if (!alg2) {
409
                if (alg)
410
                        crypto_shoot_alg(alg);
411
                return ERR_PTR(-EAGAIN);
412
        }
413
 
414
        tfm = ERR_PTR(-EINVAL);
415
        if (unlikely((alg->cra_flags ^ type) & mask))
416
                goto out_put_alg;
417
 
418
        tfm = __crypto_alloc_tfm(alg, type, mask);
419
        if (IS_ERR(tfm))
420
                goto out_put_alg;
421
 
422
        return tfm;
423
 
424
out_put_alg:
425
        crypto_mod_put(alg);
426
        return tfm;
427
}
428
EXPORT_SYMBOL_GPL(crypto_spawn_tfm);
429
 
430
int crypto_register_notifier(struct notifier_block *nb)
431
{
432
        return blocking_notifier_chain_register(&crypto_chain, nb);
433
}
434
EXPORT_SYMBOL_GPL(crypto_register_notifier);
435
 
436
int crypto_unregister_notifier(struct notifier_block *nb)
437
{
438
        return blocking_notifier_chain_unregister(&crypto_chain, nb);
439
}
440
EXPORT_SYMBOL_GPL(crypto_unregister_notifier);
441
 
442
struct crypto_attr_type *crypto_get_attr_type(struct rtattr **tb)
443
{
444
        struct rtattr *rta = tb[0];
445
        struct crypto_attr_type *algt;
446
 
447
        if (!rta)
448
                return ERR_PTR(-ENOENT);
449
        if (RTA_PAYLOAD(rta) < sizeof(*algt))
450
                return ERR_PTR(-EINVAL);
451
        if (rta->rta_type != CRYPTOA_TYPE)
452
                return ERR_PTR(-EINVAL);
453
 
454
        algt = RTA_DATA(rta);
455
 
456
        return algt;
457
}
458
EXPORT_SYMBOL_GPL(crypto_get_attr_type);
459
 
460
int crypto_check_attr_type(struct rtattr **tb, u32 type)
461
{
462
        struct crypto_attr_type *algt;
463
 
464
        algt = crypto_get_attr_type(tb);
465
        if (IS_ERR(algt))
466
                return PTR_ERR(algt);
467
 
468
        if ((algt->type ^ type) & algt->mask)
469
                return -EINVAL;
470
 
471
        return 0;
472
}
473
EXPORT_SYMBOL_GPL(crypto_check_attr_type);
474
 
475
struct crypto_alg *crypto_attr_alg(struct rtattr *rta, u32 type, u32 mask)
476
{
477
        struct crypto_attr_alg *alga;
478
 
479
        if (!rta)
480
                return ERR_PTR(-ENOENT);
481
        if (RTA_PAYLOAD(rta) < sizeof(*alga))
482
                return ERR_PTR(-EINVAL);
483
        if (rta->rta_type != CRYPTOA_ALG)
484
                return ERR_PTR(-EINVAL);
485
 
486
        alga = RTA_DATA(rta);
487
        alga->name[CRYPTO_MAX_ALG_NAME - 1] = 0;
488
 
489
        return crypto_alg_mod_lookup(alga->name, type, mask);
490
}
491
EXPORT_SYMBOL_GPL(crypto_attr_alg);
492
 
493
int crypto_attr_u32(struct rtattr *rta, u32 *num)
494
{
495
        struct crypto_attr_u32 *nu32;
496
 
497
        if (!rta)
498
                return -ENOENT;
499
        if (RTA_PAYLOAD(rta) < sizeof(*nu32))
500
                return -EINVAL;
501
        if (rta->rta_type != CRYPTOA_U32)
502
                return -EINVAL;
503
 
504
        nu32 = RTA_DATA(rta);
505
        *num = nu32->num;
506
 
507
        return 0;
508
}
509
EXPORT_SYMBOL_GPL(crypto_attr_u32);
510
 
511
struct crypto_instance *crypto_alloc_instance(const char *name,
512
                                              struct crypto_alg *alg)
513
{
514
        struct crypto_instance *inst;
515
        struct crypto_spawn *spawn;
516
        int err;
517
 
518
        inst = kzalloc(sizeof(*inst) + sizeof(*spawn), GFP_KERNEL);
519
        if (!inst)
520
                return ERR_PTR(-ENOMEM);
521
 
522
        err = -ENAMETOOLONG;
523
        if (snprintf(inst->alg.cra_name, CRYPTO_MAX_ALG_NAME, "%s(%s)", name,
524
                     alg->cra_name) >= CRYPTO_MAX_ALG_NAME)
525
                goto err_free_inst;
526
 
527
        if (snprintf(inst->alg.cra_driver_name, CRYPTO_MAX_ALG_NAME, "%s(%s)",
528
                     name, alg->cra_driver_name) >= CRYPTO_MAX_ALG_NAME)
529
                goto err_free_inst;
530
 
531
        spawn = crypto_instance_ctx(inst);
532
        err = crypto_init_spawn(spawn, alg, inst,
533
                                CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC);
534
 
535
        if (err)
536
                goto err_free_inst;
537
 
538
        return inst;
539
 
540
err_free_inst:
541
        kfree(inst);
542
        return ERR_PTR(err);
543
}
544
EXPORT_SYMBOL_GPL(crypto_alloc_instance);
545
 
546
void crypto_init_queue(struct crypto_queue *queue, unsigned int max_qlen)
547
{
548
        INIT_LIST_HEAD(&queue->list);
549
        queue->backlog = &queue->list;
550
        queue->qlen = 0;
551
        queue->max_qlen = max_qlen;
552
}
553
EXPORT_SYMBOL_GPL(crypto_init_queue);
554
 
555
int crypto_enqueue_request(struct crypto_queue *queue,
556
                           struct crypto_async_request *request)
557
{
558
        int err = -EINPROGRESS;
559
 
560
        if (unlikely(queue->qlen >= queue->max_qlen)) {
561
                err = -EBUSY;
562
                if (!(request->flags & CRYPTO_TFM_REQ_MAY_BACKLOG))
563
                        goto out;
564
                if (queue->backlog == &queue->list)
565
                        queue->backlog = &request->list;
566
        }
567
 
568
        queue->qlen++;
569
        list_add_tail(&request->list, &queue->list);
570
 
571
out:
572
        return err;
573
}
574
EXPORT_SYMBOL_GPL(crypto_enqueue_request);
575
 
576
struct crypto_async_request *crypto_dequeue_request(struct crypto_queue *queue)
577
{
578
        struct list_head *request;
579
 
580
        if (unlikely(!queue->qlen))
581
                return NULL;
582
 
583
        queue->qlen--;
584
 
585
        if (queue->backlog != &queue->list)
586
                queue->backlog = queue->backlog->next;
587
 
588
        request = queue->list.next;
589
        list_del(request);
590
 
591
        return list_entry(request, struct crypto_async_request, list);
592
}
593
EXPORT_SYMBOL_GPL(crypto_dequeue_request);
594
 
595
int crypto_tfm_in_queue(struct crypto_queue *queue, struct crypto_tfm *tfm)
596
{
597
        struct crypto_async_request *req;
598
 
599
        list_for_each_entry(req, &queue->list, list) {
600
                if (req->tfm == tfm)
601
                        return 1;
602
        }
603
 
604
        return 0;
605
}
606
EXPORT_SYMBOL_GPL(crypto_tfm_in_queue);
607
 
608
static int __init crypto_algapi_init(void)
609
{
610
        crypto_init_proc();
611
        return 0;
612
}
613
 
614
static void __exit crypto_algapi_exit(void)
615
{
616
        crypto_exit_proc();
617
}
618
 
619
module_init(crypto_algapi_init);
620
module_exit(crypto_algapi_exit);
621
 
622
MODULE_LICENSE("GPL");
623
MODULE_DESCRIPTION("Cryptographic algorithms API");

powered by: WebSVN 2.1.0

© copyright 1999-2025 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.