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 /crypto | |
| 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>
Diffstat (limited to 'crypto')
| -rw-r--r-- | crypto/algapi.c | 50 | ||||
| -rw-r--r-- | crypto/api.c | 122 | ||||
| -rw-r--r-- | crypto/internal.h | 37 |
3 files changed, 196 insertions, 13 deletions
diff --git a/crypto/algapi.c b/crypto/algapi.c index 232b37d816..f0df85fc1f 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 c922090b48..5a0d6a17cf 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 c3ab4a950f..3a08d25fba 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 | ||
