aboutsummaryrefslogtreecommitdiffstats
path: root/crypto/api.c
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/api.c')
-rw-r--r--crypto/api.c122
1 files changed, 110 insertions, 12 deletions
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)