diff options
author | Herbert Xu <herbert@gondor.apana.org.au> | 2006-08-06 07:23:26 -0400 |
---|---|---|
committer | Herbert Xu <herbert@gondor.apana.org.au> | 2006-09-20 21:17:13 -0400 |
commit | 2825982d9d66ebba4b532a07391dfbb357f71c5f (patch) | |
tree | 3789b26b593d081ff8eedc7e528c2b9b49a94dc2 | |
parent | 4cc7720cd165273b08a72b4193146dffee58e34b (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>
-rw-r--r-- | crypto/algapi.c | 50 | ||||
-rw-r--r-- | crypto/api.c | 122 | ||||
-rw-r--r-- | crypto/internal.h | 37 | ||||
-rw-r--r-- | include/linux/crypto.h | 4 |
4 files changed, 199 insertions, 14 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 | ||
22 | static LIST_HEAD(crypto_template_list); | 22 | static LIST_HEAD(crypto_template_list); |
23 | 23 | ||
24 | void 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 | } | ||
40 | EXPORT_SYMBOL_GPL(crypto_larval_error); | ||
41 | |||
24 | static inline int crypto_set_driver_name(struct crypto_alg *alg) | 42 | static 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 | |||
71 | out: | 102 | out: |
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; |
127 | out: | 160 | out: |
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 | } |
213 | EXPORT_SYMBOL_GPL(crypto_register_instance); | 249 | EXPORT_SYMBOL_GPL(crypto_register_instance); |
214 | 250 | ||
251 | int crypto_register_notifier(struct notifier_block *nb) | ||
252 | { | ||
253 | return blocking_notifier_chain_register(&crypto_chain, nb); | ||
254 | } | ||
255 | EXPORT_SYMBOL_GPL(crypto_register_notifier); | ||
256 | |||
257 | int crypto_unregister_notifier(struct notifier_block *nb) | ||
258 | { | ||
259 | return blocking_notifier_chain_unregister(&crypto_chain, nb); | ||
260 | } | ||
261 | EXPORT_SYMBOL_GPL(crypto_unregister_notifier); | ||
262 | |||
215 | static int __init crypto_algapi_init(void) | 263 | static 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); | |||
27 | DECLARE_RWSEM(crypto_alg_sem); | 28 | DECLARE_RWSEM(crypto_alg_sem); |
28 | EXPORT_SYMBOL_GPL(crypto_alg_sem); | 29 | EXPORT_SYMBOL_GPL(crypto_alg_sem); |
29 | 30 | ||
31 | BLOCKING_NOTIFIER_HEAD(crypto_chain); | ||
32 | EXPORT_SYMBOL_GPL(crypto_chain); | ||
33 | |||
30 | static inline struct crypto_alg *crypto_alg_get(struct crypto_alg *alg) | 34 | static 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 | ||
42 | static struct crypto_alg *crypto_mod_get(struct crypto_alg *alg) | 46 | struct 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 | } |
50 | EXPORT_SYMBOL_GPL(crypto_mod_get); | ||
46 | 51 | ||
47 | static void crypto_mod_put(struct crypto_alg *alg) | 52 | void 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 | } |
57 | EXPORT_SYMBOL_GPL(crypto_mod_put); | ||
52 | 58 | ||
53 | static struct crypto_alg *crypto_alg_lookup(const char *name) | 59 | struct 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 | } | ||
86 | EXPORT_SYMBOL_GPL(__crypto_alg_lookup); | ||
87 | |||
88 | static 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 | |||
98 | static 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 | |||
129 | static 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 | |||
140 | static 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 | |||
153 | static 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. */ |
89 | static inline struct crypto_alg *crypto_alg_mod_lookup(const char *name) | 169 | static 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 | ||
94 | static int crypto_init_flags(struct crypto_tfm *tfm, u32 flags) | 192 | static 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. */ | ||
31 | enum { | ||
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 | |||
28 | struct crypto_instance; | 39 | struct crypto_instance; |
29 | struct crypto_template; | 40 | struct crypto_template; |
30 | 41 | ||
42 | struct crypto_larval { | ||
43 | struct crypto_alg alg; | ||
44 | struct crypto_alg *adult; | ||
45 | struct completion completion; | ||
46 | }; | ||
47 | |||
31 | extern struct list_head crypto_alg_list; | 48 | extern struct list_head crypto_alg_list; |
32 | extern struct rw_semaphore crypto_alg_sem; | 49 | extern struct rw_semaphore crypto_alg_sem; |
50 | extern struct blocking_notifier_head crypto_chain; | ||
33 | 51 | ||
34 | extern enum km_type crypto_km_types[]; | 52 | extern 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 | ||
125 | struct crypto_alg *crypto_mod_get(struct crypto_alg *alg); | ||
126 | void crypto_mod_put(struct crypto_alg *alg); | ||
127 | struct crypto_alg *__crypto_alg_lookup(const char *name); | ||
128 | |||
107 | int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags); | 129 | int crypto_init_digest_flags(struct crypto_tfm *tfm, u32 flags); |
108 | int crypto_init_cipher_flags(struct crypto_tfm *tfm, u32 flags); | 130 | int crypto_init_cipher_flags(struct crypto_tfm *tfm, u32 flags); |
109 | int crypto_init_compress_flags(struct crypto_tfm *tfm, u32 flags); | 131 | int crypto_init_compress_flags(struct crypto_tfm *tfm, u32 flags); |
@@ -116,9 +138,14 @@ void crypto_exit_digest_ops(struct crypto_tfm *tfm); | |||
116 | void crypto_exit_cipher_ops(struct crypto_tfm *tfm); | 138 | void crypto_exit_cipher_ops(struct crypto_tfm *tfm); |
117 | void crypto_exit_compress_ops(struct crypto_tfm *tfm); | 139 | void crypto_exit_compress_ops(struct crypto_tfm *tfm); |
118 | 140 | ||
141 | void crypto_larval_error(const char *name); | ||
142 | |||
119 | int crypto_register_instance(struct crypto_template *tmpl, | 143 | int crypto_register_instance(struct crypto_template *tmpl, |
120 | struct crypto_instance *inst); | 144 | struct crypto_instance *inst); |
121 | 145 | ||
146 | int crypto_register_notifier(struct notifier_block *nb); | ||
147 | int crypto_unregister_notifier(struct notifier_block *nb); | ||
148 | |||
122 | static inline int crypto_tmpl_get(struct crypto_template *tmpl) | 149 | static 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 | ||
159 | static inline int crypto_is_larval(struct crypto_alg *alg) | ||
160 | { | ||
161 | return alg->cra_flags & CRYPTO_ALG_LARVAL; | ||
162 | } | ||
163 | |||
164 | static 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 | ||
diff --git a/include/linux/crypto.h b/include/linux/crypto.h index 7f57ff8ec975..3e3e95aff133 100644 --- a/include/linux/crypto.h +++ b/include/linux/crypto.h | |||
@@ -29,11 +29,13 @@ | |||
29 | /* | 29 | /* |
30 | * Algorithm masks and types. | 30 | * Algorithm masks and types. |
31 | */ | 31 | */ |
32 | #define CRYPTO_ALG_TYPE_MASK 0x000000ff | 32 | #define CRYPTO_ALG_TYPE_MASK 0x0000000f |
33 | #define CRYPTO_ALG_TYPE_CIPHER 0x00000001 | 33 | #define CRYPTO_ALG_TYPE_CIPHER 0x00000001 |
34 | #define CRYPTO_ALG_TYPE_DIGEST 0x00000002 | 34 | #define CRYPTO_ALG_TYPE_DIGEST 0x00000002 |
35 | #define CRYPTO_ALG_TYPE_COMPRESS 0x00000004 | 35 | #define CRYPTO_ALG_TYPE_COMPRESS 0x00000004 |
36 | 36 | ||
37 | #define CRYPTO_ALG_LARVAL 0x00000010 | ||
38 | |||
37 | /* | 39 | /* |
38 | * Transform masks and values (for crt_flags). | 40 | * Transform masks and values (for crt_flags). |
39 | */ | 41 | */ |