diff options
Diffstat (limited to 'crypto/api.c')
-rw-r--r-- | crypto/api.c | 73 |
1 files changed, 58 insertions, 15 deletions
diff --git a/crypto/api.c b/crypto/api.c index 0906cedd4521..0444d242e985 100644 --- a/crypto/api.c +++ b/crypto/api.c | |||
@@ -55,6 +55,11 @@ void crypto_mod_put(struct crypto_alg *alg) | |||
55 | } | 55 | } |
56 | EXPORT_SYMBOL_GPL(crypto_mod_put); | 56 | EXPORT_SYMBOL_GPL(crypto_mod_put); |
57 | 57 | ||
58 | static inline int crypto_is_test_larval(struct crypto_larval *larval) | ||
59 | { | ||
60 | return larval->alg.cra_driver_name[0]; | ||
61 | } | ||
62 | |||
58 | static struct crypto_alg *__crypto_alg_lookup(const char *name, u32 type, | 63 | static struct crypto_alg *__crypto_alg_lookup(const char *name, u32 type, |
59 | u32 mask) | 64 | u32 mask) |
60 | { | 65 | { |
@@ -71,6 +76,7 @@ static struct crypto_alg *__crypto_alg_lookup(const char *name, u32 type, | |||
71 | continue; | 76 | continue; |
72 | 77 | ||
73 | if (crypto_is_larval(q) && | 78 | if (crypto_is_larval(q) && |
79 | !crypto_is_test_larval((struct crypto_larval *)q) && | ||
74 | ((struct crypto_larval *)q)->mask != mask) | 80 | ((struct crypto_larval *)q)->mask != mask) |
75 | continue; | 81 | continue; |
76 | 82 | ||
@@ -104,10 +110,8 @@ static void crypto_larval_destroy(struct crypto_alg *alg) | |||
104 | kfree(larval); | 110 | kfree(larval); |
105 | } | 111 | } |
106 | 112 | ||
107 | static struct crypto_alg *crypto_larval_alloc(const char *name, u32 type, | 113 | struct crypto_larval *crypto_larval_alloc(const char *name, u32 type, u32 mask) |
108 | u32 mask) | ||
109 | { | 114 | { |
110 | struct crypto_alg *alg; | ||
111 | struct crypto_larval *larval; | 115 | struct crypto_larval *larval; |
112 | 116 | ||
113 | larval = kzalloc(sizeof(*larval), GFP_KERNEL); | 117 | larval = kzalloc(sizeof(*larval), GFP_KERNEL); |
@@ -119,10 +123,25 @@ static struct crypto_alg *crypto_larval_alloc(const char *name, u32 type, | |||
119 | larval->alg.cra_priority = -1; | 123 | larval->alg.cra_priority = -1; |
120 | larval->alg.cra_destroy = crypto_larval_destroy; | 124 | larval->alg.cra_destroy = crypto_larval_destroy; |
121 | 125 | ||
122 | atomic_set(&larval->alg.cra_refcnt, 2); | ||
123 | strlcpy(larval->alg.cra_name, name, CRYPTO_MAX_ALG_NAME); | 126 | strlcpy(larval->alg.cra_name, name, CRYPTO_MAX_ALG_NAME); |
124 | init_completion(&larval->completion); | 127 | init_completion(&larval->completion); |
125 | 128 | ||
129 | return larval; | ||
130 | } | ||
131 | EXPORT_SYMBOL_GPL(crypto_larval_alloc); | ||
132 | |||
133 | static struct crypto_alg *crypto_larval_add(const char *name, u32 type, | ||
134 | u32 mask) | ||
135 | { | ||
136 | struct crypto_alg *alg; | ||
137 | struct crypto_larval *larval; | ||
138 | |||
139 | larval = crypto_larval_alloc(name, type, mask); | ||
140 | if (IS_ERR(larval)) | ||
141 | return ERR_CAST(larval); | ||
142 | |||
143 | atomic_set(&larval->alg.cra_refcnt, 2); | ||
144 | |||
126 | down_write(&crypto_alg_sem); | 145 | down_write(&crypto_alg_sem); |
127 | alg = __crypto_alg_lookup(name, type, mask); | 146 | alg = __crypto_alg_lookup(name, type, mask); |
128 | if (!alg) { | 147 | if (!alg) { |
@@ -152,14 +171,23 @@ EXPORT_SYMBOL_GPL(crypto_larval_kill); | |||
152 | static struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg) | 171 | static struct crypto_alg *crypto_larval_wait(struct crypto_alg *alg) |
153 | { | 172 | { |
154 | struct crypto_larval *larval = (void *)alg; | 173 | struct crypto_larval *larval = (void *)alg; |
174 | long timeout; | ||
175 | |||
176 | timeout = wait_for_completion_interruptible_timeout( | ||
177 | &larval->completion, 60 * HZ); | ||
155 | 178 | ||
156 | wait_for_completion_interruptible_timeout(&larval->completion, 60 * HZ); | ||
157 | alg = larval->adult; | 179 | alg = larval->adult; |
158 | if (alg) { | 180 | if (timeout < 0) |
159 | if (!crypto_mod_get(alg)) | 181 | alg = ERR_PTR(-EINTR); |
160 | alg = ERR_PTR(-EAGAIN); | 182 | else if (!timeout) |
161 | } else | 183 | alg = ERR_PTR(-ETIMEDOUT); |
184 | else if (!alg) | ||
162 | alg = ERR_PTR(-ENOENT); | 185 | alg = ERR_PTR(-ENOENT); |
186 | else if (crypto_is_test_larval(larval) && | ||
187 | !(alg->cra_flags & CRYPTO_ALG_TESTED)) | ||
188 | alg = ERR_PTR(-EAGAIN); | ||
189 | else if (!crypto_mod_get(alg)) | ||
190 | alg = ERR_PTR(-EAGAIN); | ||
163 | crypto_mod_put(&larval->alg); | 191 | crypto_mod_put(&larval->alg); |
164 | 192 | ||
165 | return alg; | 193 | return alg; |
@@ -192,25 +220,40 @@ struct crypto_alg *crypto_larval_lookup(const char *name, u32 type, u32 mask) | |||
192 | if (alg) | 220 | if (alg) |
193 | return crypto_is_larval(alg) ? crypto_larval_wait(alg) : alg; | 221 | return crypto_is_larval(alg) ? crypto_larval_wait(alg) : alg; |
194 | 222 | ||
195 | return crypto_larval_alloc(name, type, mask); | 223 | return crypto_larval_add(name, type, mask); |
196 | } | 224 | } |
197 | EXPORT_SYMBOL_GPL(crypto_larval_lookup); | 225 | EXPORT_SYMBOL_GPL(crypto_larval_lookup); |
198 | 226 | ||
227 | int crypto_probing_notify(unsigned long val, void *v) | ||
228 | { | ||
229 | int ok; | ||
230 | |||
231 | ok = blocking_notifier_call_chain(&crypto_chain, val, v); | ||
232 | if (ok == NOTIFY_DONE) { | ||
233 | request_module("cryptomgr"); | ||
234 | ok = blocking_notifier_call_chain(&crypto_chain, val, v); | ||
235 | } | ||
236 | |||
237 | return ok; | ||
238 | } | ||
239 | EXPORT_SYMBOL_GPL(crypto_probing_notify); | ||
240 | |||
199 | struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask) | 241 | struct crypto_alg *crypto_alg_mod_lookup(const char *name, u32 type, u32 mask) |
200 | { | 242 | { |
201 | struct crypto_alg *alg; | 243 | struct crypto_alg *alg; |
202 | struct crypto_alg *larval; | 244 | struct crypto_alg *larval; |
203 | int ok; | 245 | int ok; |
204 | 246 | ||
247 | if (!(mask & CRYPTO_ALG_TESTED)) { | ||
248 | type |= CRYPTO_ALG_TESTED; | ||
249 | mask |= CRYPTO_ALG_TESTED; | ||
250 | } | ||
251 | |||
205 | larval = crypto_larval_lookup(name, type, mask); | 252 | larval = crypto_larval_lookup(name, type, mask); |
206 | if (IS_ERR(larval) || !crypto_is_larval(larval)) | 253 | if (IS_ERR(larval) || !crypto_is_larval(larval)) |
207 | return larval; | 254 | return larval; |
208 | 255 | ||
209 | ok = crypto_notify(CRYPTO_MSG_ALG_REQUEST, larval); | 256 | ok = crypto_probing_notify(CRYPTO_MSG_ALG_REQUEST, larval); |
210 | if (ok == NOTIFY_DONE) { | ||
211 | request_module("cryptomgr"); | ||
212 | ok = crypto_notify(CRYPTO_MSG_ALG_REQUEST, larval); | ||
213 | } | ||
214 | 257 | ||
215 | if (ok == NOTIFY_STOP) | 258 | if (ok == NOTIFY_STOP) |
216 | alg = crypto_larval_wait(larval); | 259 | alg = crypto_larval_wait(larval); |