aboutsummaryrefslogtreecommitdiffstats
path: root/crypto
diff options
context:
space:
mode:
authorHerbert Xu <herbert@gondor.apana.org.au>2006-08-06 07:23:26 -0400
committerHerbert Xu <herbert@gondor.apana.org.au>2006-09-20 21:17:13 -0400
commit2825982d9d66ebba4b532a07391dfbb357f71c5f (patch)
tree3789b26b593d081ff8eedc7e528c2b9b49a94dc2 /crypto
parent4cc7720cd165273b08a72b4193146dffee58e34b (diff)
[CRYPTO] api: Added event notification
This patch adds a notifier chain for algorithm/template registration events. This will be used to register compound algorithms such as cbc(aes). In future this will also be passed onto user-space through netlink. Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'crypto')
-rw-r--r--crypto/algapi.c50
-rw-r--r--crypto/api.c122
-rw-r--r--crypto/internal.h37
3 files changed, 196 insertions, 13 deletions
diff --git a/crypto/algapi.c b/crypto/algapi.c
index 232b37d81613..f0df85fc1f50 100644
--- a/crypto/algapi.c
+++ b/crypto/algapi.c
@@ -21,6 +21,24 @@
21 21
22static LIST_HEAD(crypto_template_list); 22static LIST_HEAD(crypto_template_list);
23 23
24void crypto_larval_error(const char *name)
25{
26 struct crypto_alg *alg;
27
28 down_read(&crypto_alg_sem);
29 alg = __crypto_alg_lookup(name);
30 up_read(&crypto_alg_sem);
31
32 if (alg) {
33 if (crypto_is_larval(alg)) {
34 struct crypto_larval *larval = (void *)alg;
35 complete(&larval->completion);
36 }
37 crypto_mod_put(alg);
38 }
39}
40EXPORT_SYMBOL_GPL(crypto_larval_error);
41
24static inline int crypto_set_driver_name(struct crypto_alg *alg) 42static inline int crypto_set_driver_name(struct crypto_alg *alg)
25{ 43{
26 static const char suffix[] = "-generic"; 44 static const char suffix[] = "-generic";
@@ -60,14 +78,27 @@ static int __crypto_register_alg(struct crypto_alg *alg)
60 struct crypto_alg *q; 78 struct crypto_alg *q;
61 int ret = -EEXIST; 79 int ret = -EEXIST;
62 80
81 atomic_set(&alg->cra_refcnt, 1);
63 list_for_each_entry(q, &crypto_alg_list, cra_list) { 82 list_for_each_entry(q, &crypto_alg_list, cra_list) {
64 if (q == alg) 83 if (q == alg)
65 goto out; 84 goto out;
85 if (crypto_is_larval(q) &&
86 (!strcmp(alg->cra_name, q->cra_name) ||
87 !strcmp(alg->cra_driver_name, q->cra_name))) {
88 struct crypto_larval *larval = (void *)q;
89
90 if (!crypto_mod_get(alg))
91 continue;
92 larval->adult = alg;
93 complete(&larval->completion);
94 }
66 } 95 }
67 96
68 list_add(&alg->cra_list, &crypto_alg_list); 97 list_add(&alg->cra_list, &crypto_alg_list);
69 atomic_set(&alg->cra_refcnt, 1); 98
99 crypto_notify(CRYPTO_MSG_ALG_REGISTER, alg);
70 ret = 0; 100 ret = 0;
101
71out: 102out:
72 return ret; 103 return ret;
73} 104}
@@ -97,6 +128,7 @@ int crypto_unregister_alg(struct crypto_alg *alg)
97 list_del_init(&alg->cra_list); 128 list_del_init(&alg->cra_list);
98 ret = 0; 129 ret = 0;
99 } 130 }
131 crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, alg);
100 up_write(&crypto_alg_sem); 132 up_write(&crypto_alg_sem);
101 133
102 if (ret) 134 if (ret)
@@ -123,6 +155,7 @@ int crypto_register_template(struct crypto_template *tmpl)
123 } 155 }
124 156
125 list_add(&tmpl->list, &crypto_template_list); 157 list_add(&tmpl->list, &crypto_template_list);
158 crypto_notify(CRYPTO_MSG_TMPL_REGISTER, tmpl);
126 err = 0; 159 err = 0;
127out: 160out:
128 up_write(&crypto_alg_sem); 161 up_write(&crypto_alg_sem);
@@ -145,8 +178,11 @@ void crypto_unregister_template(struct crypto_template *tmpl)
145 hlist_for_each_entry(inst, p, list, list) { 178 hlist_for_each_entry(inst, p, list, list) {
146 BUG_ON(list_empty(&inst->alg.cra_list)); 179 BUG_ON(list_empty(&inst->alg.cra_list));
147 list_del_init(&inst->alg.cra_list); 180 list_del_init(&inst->alg.cra_list);
181 crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, &inst->alg);
148 } 182 }
149 183
184 crypto_notify(CRYPTO_MSG_TMPL_UNREGISTER, tmpl);
185
150 up_write(&crypto_alg_sem); 186 up_write(&crypto_alg_sem);
151 187
152 hlist_for_each_entry_safe(inst, p, n, list, list) { 188 hlist_for_each_entry_safe(inst, p, n, list, list) {
@@ -212,6 +248,18 @@ err:
212} 248}
213EXPORT_SYMBOL_GPL(crypto_register_instance); 249EXPORT_SYMBOL_GPL(crypto_register_instance);
214 250
251int crypto_register_notifier(struct notifier_block *nb)
252{
253 return blocking_notifier_chain_register(&crypto_chain, nb);
254}
255EXPORT_SYMBOL_GPL(crypto_register_notifier);
256
257int crypto_unregister_notifier(struct notifier_block *nb)
258{
259 return blocking_notifier_chain_unregister(&crypto_chain, nb);
260}
261EXPORT_SYMBOL_GPL(crypto_unregister_notifier);
262
215static int __init crypto_algapi_init(void) 263static int __init crypto_algapi_init(void)
216{ 264{
217 crypto_init_proc(); 265 crypto_init_proc();
diff --git a/crypto/api.c b/crypto/api.c
index c922090b4842..5a0d6a17cfd7 100644
--- a/crypto/api.c
+++ b/crypto/api.c
@@ -18,6 +18,7 @@
18#include <linux/errno.h> 18#include <linux/errno.h>
19#include <linux/kernel.h> 19#include <linux/kernel.h>
20#include <linux/kmod.h> 20#include <linux/kmod.h>
21#include <linux/param.h>
21#include <linux/slab.h> 22#include <linux/slab.h>
22#include <linux/string.h> 23#include <linux/string.h>
23#include "internal.h" 24#include "internal.h"
@@ -27,6 +28,9 @@ EXPORT_SYMBOL_GPL(crypto_alg_list);
27DECLARE_RWSEM(crypto_alg_sem); 28DECLARE_RWSEM(crypto_alg_sem);
28EXPORT_SYMBOL_GPL(crypto_alg_sem); 29EXPORT_SYMBOL_GPL(crypto_alg_sem);
29 30
31BLOCKING_NOTIFIER_HEAD(crypto_chain);
32EXPORT_SYMBOL_GPL(crypto_chain);
33
30static inline struct crypto_alg *crypto_alg_get(struct crypto_alg *alg) 34static inline struct crypto_alg *crypto_alg_get(struct crypto_alg *alg)
31{ 35{
32 atomic_inc(&alg->cra_refcnt); 36 atomic_inc(&alg->cra_refcnt);
@@ -39,27 +43,24 @@ static inline void crypto_alg_put(struct crypto_alg *alg)
39 alg->cra_destroy(alg); 43 alg->cra_destroy(alg);
40} 44}
41 45
42static struct crypto_alg *crypto_mod_get(struct crypto_alg *alg) 46struct crypto_alg *crypto_mod_get(struct crypto_alg *alg)
43{ 47{
44 return try_module_get(alg->cra_module) ? crypto_alg_get(alg) : NULL; 48 return try_module_get(alg->cra_module) ? crypto_alg_get(alg) : NULL;
45} 49}
50EXPORT_SYMBOL_GPL(crypto_mod_get);
46 51
47static void crypto_mod_put(struct crypto_alg *alg) 52void crypto_mod_put(struct crypto_alg *alg)
48{ 53{
49 crypto_alg_put(alg); 54 crypto_alg_put(alg);
50 module_put(alg->cra_module); 55 module_put(alg->cra_module);
51} 56}
57EXPORT_SYMBOL_GPL(crypto_mod_put);
52 58
53static struct crypto_alg *crypto_alg_lookup(const char *name) 59struct crypto_alg *__crypto_alg_lookup(const char *name)
54{ 60{
55 struct crypto_alg *q, *alg = NULL; 61 struct crypto_alg *q, *alg = NULL;
56 int best = -1; 62 int best = -2;
57 63
58 if (!name)
59 return NULL;
60
61 down_read(&crypto_alg_sem);
62
63 list_for_each_entry(q, &crypto_alg_list, cra_list) { 64 list_for_each_entry(q, &crypto_alg_list, cra_list) {
64 int exact, fuzzy; 65 int exact, fuzzy;
65 66
@@ -79,16 +80,113 @@ static struct crypto_alg *crypto_alg_lookup(const char *name)
79 if (exact) 80 if (exact)
80 break; 81 break;
81 } 82 }
82 83
84 return alg;
85}
86EXPORT_SYMBOL_GPL(__crypto_alg_lookup);
87
88static void crypto_larval_destroy(struct crypto_alg *alg)
89{
90 struct crypto_larval *larval = (void *)alg;
91
92 BUG_ON(!crypto_is_larval(alg));
93 if (larval->adult)
94 crypto_mod_put(larval->adult);
95 kfree(larval);
96}
97
98static struct crypto_alg *crypto_larval_alloc(const char *name)
99{
100 struct crypto_alg *alg;
101 struct crypto_larval *larval;
102
103 larval = kzalloc(sizeof(*larval), GFP_KERNEL);
104 if (!larval)
105 return NULL;
106
107 larval->alg.cra_flags = CRYPTO_ALG_LARVAL;
108 larval->alg.cra_priority = -1;
109 larval->alg.cra_destroy = crypto_larval_destroy;
110
111 atomic_set(&larval->alg.cra_refcnt, 2);
112 strlcpy(larval->alg.cra_name, name, CRYPTO_MAX_ALG_NAME);
113 init_completion(&larval->completion);
114
115 down_write(&crypto_alg_sem);
116 alg = __crypto_alg_lookup(name);
117 if (!alg) {
118 alg = &larval->alg;
119 list_add(&alg->cra_list, &crypto_alg_list);
120 }
121 up_write(&crypto_alg_sem);
122
123 if (alg != &larval->alg)
124 kfree(larval);
125
126 return alg;
127}
128
129static void crypto_larval_kill(struct crypto_alg *alg)
130{
131 struct crypto_larval *larval = (void *)alg;
132
133 down_write(&crypto_alg_sem);
134 list_del(&alg->cra_list);
135 up_write(&crypto_alg_sem);
136 complete(&larval->completion);
137 crypto_alg_put(alg);
138}
139
140static struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg)
141{
142 struct crypto_larval *larval = (void *)alg;
143
144 wait_for_completion_interruptible_timeout(&larval->completion, 60 * HZ);
145 alg = larval->adult;
146 if (alg && !crypto_mod_get(alg))
147 alg = NULL;
148 crypto_mod_put(&larval->alg);
149
150 return alg;
151}
152
153static struct crypto_alg *crypto_alg_lookup(const char *name)
154{
155 struct crypto_alg *alg;
156
157 if (!name)
158 return NULL;
159
160 down_read(&crypto_alg_sem);
161 alg = __crypto_alg_lookup(name);
83 up_read(&crypto_alg_sem); 162 up_read(&crypto_alg_sem);
163
84 return alg; 164 return alg;
85} 165}
86 166
87/* A far more intelligent version of this is planned. For now, just 167/* A far more intelligent version of this is planned. For now, just
88 * try an exact match on the name of the algorithm. */ 168 * try an exact match on the name of the algorithm. */
89static inline struct crypto_alg *crypto_alg_mod_lookup(const char *name) 169static struct crypto_alg *crypto_alg_mod_lookup(const char *name)
90{ 170{
91 return try_then_request_module(crypto_alg_lookup(name), name); 171 struct crypto_alg *alg;
172 struct crypto_alg *larval;
173
174 alg = try_then_request_module(crypto_alg_lookup(name), name);
175 if (alg)
176 return crypto_is_larval(alg) ? crypto_larval_wait(alg) : alg;
177
178 larval = crypto_larval_alloc(name);
179 if (!larval || !crypto_is_larval(larval))
180 return larval;
181
182 if (crypto_notify(CRYPTO_MSG_ALG_REQUEST, larval) == NOTIFY_STOP)
183 alg = crypto_larval_wait(larval);
184 else {
185 crypto_mod_put(larval);
186 alg = NULL;
187 }
188 crypto_larval_kill(larval);
189 return alg;
92} 190}
93 191
94static int crypto_init_flags(struct crypto_tfm *tfm, u32 flags) 192static int crypto_init_flags(struct crypto_tfm *tfm, u32 flags)
diff --git a/crypto/internal.h b/crypto/internal.h
index c3ab4a950f30..3a08d25fba45 100644
--- a/crypto/internal.h
+++ b/crypto/internal.h
@@ -14,6 +14,7 @@
14#define _CRYPTO_INTERNAL_H 14#define _CRYPTO_INTERNAL_H
15 15
16#include <crypto/algapi.h> 16#include <crypto/algapi.h>
17#include <linux/completion.h>
17#include <linux/mm.h> 18#include <linux/mm.h>
18#include <linux/highmem.h> 19#include <linux/highmem.h>
19#include <linux/interrupt.h> 20#include <linux/interrupt.h>
@@ -21,15 +22,32 @@
21#include <linux/list.h> 22#include <linux/list.h>
22#include <linux/module.h> 23#include <linux/module.h>
23#include <linux/kernel.h> 24#include <linux/kernel.h>
25#include <linux/notifier.h>
24#include <linux/rwsem.h> 26#include <linux/rwsem.h>
25#include <linux/slab.h> 27#include <linux/slab.h>
26#include <asm/kmap_types.h> 28#include <asm/kmap_types.h>
27 29
30/* Crypto notification events. */
31enum {
32 CRYPTO_MSG_ALG_REQUEST,
33 CRYPTO_MSG_ALG_REGISTER,
34 CRYPTO_MSG_ALG_UNREGISTER,
35 CRYPTO_MSG_TMPL_REGISTER,
36 CRYPTO_MSG_TMPL_UNREGISTER,
37};
38
28struct crypto_instance; 39struct crypto_instance;
29struct crypto_template; 40struct crypto_template;
30 41
42struct crypto_larval {
43 struct crypto_alg alg;
44 struct crypto_alg *adult;
45 struct completion completion;
46};
47
31extern struct list_head crypto_alg_list; 48extern struct list_head crypto_alg_list;
32extern struct rw_semaphore crypto_alg_sem; 49extern struct rw_semaphore crypto_alg_sem;
50extern struct blocking_notifier_head crypto_chain;
33 51
34extern enum km_type crypto_km_types[]; 52extern enum km_type crypto_km_types[];
35 53
@@ -104,6 +122,10 @@ static inline unsigned int crypto_compress_ctxsize(struct crypto_alg *alg,
104 return alg->cra_ctxsize; 122 return alg->cra_ctxsize;
105} 123}
106 124
125struct crypto_alg *crypto_mod_get(struct crypto_alg *alg);
126void crypto_mod_put(struct crypto_alg *alg);
127struct crypto_alg *__crypto_alg_lookup(const char *name);
128
107int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags); 129int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags);
108int crypto_init_cipher_flags(struct crypto_tfm *tfm, u32 flags); 130int crypto_init_cipher_flags(struct crypto_tfm *tfm, u32 flags);
109int crypto_init_compress_flags(struct crypto_tfm *tfm, u32 flags); 131int crypto_init_compress_flags(struct crypto_tfm *tfm, u32 flags);
@@ -116,9 +138,14 @@ void crypto_exit_digest_ops(struct crypto_tfm *tfm);
116void crypto_exit_cipher_ops(struct crypto_tfm *tfm); 138void crypto_exit_cipher_ops(struct crypto_tfm *tfm);
117void crypto_exit_compress_ops(struct crypto_tfm *tfm); 139void crypto_exit_compress_ops(struct crypto_tfm *tfm);
118 140
141void crypto_larval_error(const char *name);
142
119int crypto_register_instance(struct crypto_template *tmpl, 143int crypto_register_instance(struct crypto_template *tmpl,
120 struct crypto_instance *inst); 144 struct crypto_instance *inst);
121 145
146int crypto_register_notifier(struct notifier_block *nb);
147int crypto_unregister_notifier(struct notifier_block *nb);
148
122static inline int crypto_tmpl_get(struct crypto_template *tmpl) 149static inline int crypto_tmpl_get(struct crypto_template *tmpl)
123{ 150{
124 return try_module_get(tmpl->module); 151 return try_module_get(tmpl->module);
@@ -129,5 +156,15 @@ static inline void crypto_tmpl_put(struct crypto_template *tmpl)
129 module_put(tmpl->module); 156 module_put(tmpl->module);
130} 157}
131 158
159static inline int crypto_is_larval(struct crypto_alg *alg)
160{
161 return alg->cra_flags & CRYPTO_ALG_LARVAL;
162}
163
164static inline int crypto_notify(unsigned long val, void *v)
165{
166 return blocking_notifier_call_chain(&crypto_chain, val, v);
167}
168
132#endif /* _CRYPTO_INTERNAL_H */ 169#endif /* _CRYPTO_INTERNAL_H */
133 170