Herbert Xu | cce9e06 | 2006-08-21 21:08:13 +1000 | [diff] [blame] | 1 | /* |
| 2 | * Cryptographic API for algorithms (i.e., low-level API). |
| 3 | * |
| 4 | * Copyright (c) 2006 Herbert Xu <herbert@gondor.apana.org.au> |
| 5 | * |
| 6 | * This program is free software; you can redistribute it and/or modify it |
| 7 | * under the terms of the GNU General Public License as published by the Free |
| 8 | * Software Foundation; either version 2 of the License, or (at your option) |
| 9 | * any later version. |
| 10 | * |
| 11 | */ |
| 12 | |
Herbert Xu | 6bfd480 | 2006-09-21 11:39:29 +1000 | [diff] [blame^] | 13 | #include <linux/err.h> |
Herbert Xu | cce9e06 | 2006-08-21 21:08:13 +1000 | [diff] [blame] | 14 | #include <linux/errno.h> |
| 15 | #include <linux/init.h> |
| 16 | #include <linux/kernel.h> |
Herbert Xu | 4cc7720 | 2006-08-06 21:16:34 +1000 | [diff] [blame] | 17 | #include <linux/list.h> |
Herbert Xu | cce9e06 | 2006-08-21 21:08:13 +1000 | [diff] [blame] | 18 | #include <linux/module.h> |
| 19 | #include <linux/string.h> |
| 20 | |
| 21 | #include "internal.h" |
| 22 | |
Herbert Xu | 4cc7720 | 2006-08-06 21:16:34 +1000 | [diff] [blame] | 23 | static LIST_HEAD(crypto_template_list); |
| 24 | |
Herbert Xu | 492e2b6 | 2006-09-21 11:35:17 +1000 | [diff] [blame] | 25 | void crypto_larval_error(const char *name, u32 type, u32 mask) |
Herbert Xu | 2825982 | 2006-08-06 21:23:26 +1000 | [diff] [blame] | 26 | { |
| 27 | struct crypto_alg *alg; |
| 28 | |
| 29 | down_read(&crypto_alg_sem); |
Herbert Xu | 492e2b6 | 2006-09-21 11:35:17 +1000 | [diff] [blame] | 30 | alg = __crypto_alg_lookup(name, type, mask); |
Herbert Xu | 2825982 | 2006-08-06 21:23:26 +1000 | [diff] [blame] | 31 | up_read(&crypto_alg_sem); |
| 32 | |
| 33 | if (alg) { |
| 34 | if (crypto_is_larval(alg)) { |
| 35 | struct crypto_larval *larval = (void *)alg; |
| 36 | complete(&larval->completion); |
| 37 | } |
| 38 | crypto_mod_put(alg); |
| 39 | } |
| 40 | } |
| 41 | EXPORT_SYMBOL_GPL(crypto_larval_error); |
| 42 | |
Herbert Xu | cce9e06 | 2006-08-21 21:08:13 +1000 | [diff] [blame] | 43 | static inline int crypto_set_driver_name(struct crypto_alg *alg) |
| 44 | { |
| 45 | static const char suffix[] = "-generic"; |
| 46 | char *driver_name = alg->cra_driver_name; |
| 47 | int len; |
| 48 | |
| 49 | if (*driver_name) |
| 50 | return 0; |
| 51 | |
| 52 | len = strlcpy(driver_name, alg->cra_name, CRYPTO_MAX_ALG_NAME); |
| 53 | if (len + sizeof(suffix) > CRYPTO_MAX_ALG_NAME) |
| 54 | return -ENAMETOOLONG; |
| 55 | |
| 56 | memcpy(driver_name + len, suffix, sizeof(suffix)); |
| 57 | return 0; |
| 58 | } |
| 59 | |
Herbert Xu | 4cc7720 | 2006-08-06 21:16:34 +1000 | [diff] [blame] | 60 | static int crypto_check_alg(struct crypto_alg *alg) |
Herbert Xu | cce9e06 | 2006-08-21 21:08:13 +1000 | [diff] [blame] | 61 | { |
Herbert Xu | cce9e06 | 2006-08-21 21:08:13 +1000 | [diff] [blame] | 62 | if (alg->cra_alignmask & (alg->cra_alignmask + 1)) |
| 63 | return -EINVAL; |
| 64 | |
| 65 | if (alg->cra_alignmask & alg->cra_blocksize) |
| 66 | return -EINVAL; |
| 67 | |
| 68 | if (alg->cra_blocksize > PAGE_SIZE / 8) |
| 69 | return -EINVAL; |
| 70 | |
| 71 | if (alg->cra_priority < 0) |
| 72 | return -EINVAL; |
Herbert Xu | cce9e06 | 2006-08-21 21:08:13 +1000 | [diff] [blame] | 73 | |
Herbert Xu | 4cc7720 | 2006-08-06 21:16:34 +1000 | [diff] [blame] | 74 | return crypto_set_driver_name(alg); |
| 75 | } |
| 76 | |
Herbert Xu | 6bfd480 | 2006-09-21 11:39:29 +1000 | [diff] [blame^] | 77 | static void crypto_destroy_instance(struct crypto_alg *alg) |
| 78 | { |
| 79 | struct crypto_instance *inst = (void *)alg; |
| 80 | struct crypto_template *tmpl = inst->tmpl; |
| 81 | |
| 82 | tmpl->free(inst); |
| 83 | crypto_tmpl_put(tmpl); |
| 84 | } |
| 85 | |
| 86 | static void crypto_remove_spawns(struct list_head *spawns, |
| 87 | struct list_head *list) |
| 88 | { |
| 89 | struct crypto_spawn *spawn, *n; |
| 90 | |
| 91 | list_for_each_entry_safe(spawn, n, spawns, list) { |
| 92 | struct crypto_instance *inst = spawn->inst; |
| 93 | struct crypto_template *tmpl = inst->tmpl; |
| 94 | |
| 95 | list_del_init(&spawn->list); |
| 96 | spawn->alg = NULL; |
| 97 | |
| 98 | if (crypto_is_dead(&inst->alg)) |
| 99 | continue; |
| 100 | |
| 101 | inst->alg.cra_flags |= CRYPTO_ALG_DEAD; |
| 102 | if (!tmpl || !crypto_tmpl_get(tmpl)) |
| 103 | continue; |
| 104 | |
| 105 | crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, &inst->alg); |
| 106 | list_move(&inst->alg.cra_list, list); |
| 107 | hlist_del(&inst->list); |
| 108 | inst->alg.cra_destroy = crypto_destroy_instance; |
| 109 | |
| 110 | if (!list_empty(&inst->alg.cra_users)) { |
| 111 | if (&n->list == spawns) |
| 112 | n = list_entry(inst->alg.cra_users.next, |
| 113 | typeof(*n), list); |
| 114 | __list_splice(&inst->alg.cra_users, spawns->prev); |
| 115 | } |
| 116 | } |
| 117 | } |
| 118 | |
| 119 | static int __crypto_register_alg(struct crypto_alg *alg, |
| 120 | struct list_head *list) |
Herbert Xu | 4cc7720 | 2006-08-06 21:16:34 +1000 | [diff] [blame] | 121 | { |
| 122 | struct crypto_alg *q; |
Herbert Xu | 6bfd480 | 2006-09-21 11:39:29 +1000 | [diff] [blame^] | 123 | int ret = -EAGAIN; |
| 124 | |
| 125 | if (crypto_is_dead(alg)) |
| 126 | goto out; |
| 127 | |
| 128 | INIT_LIST_HEAD(&alg->cra_users); |
| 129 | |
| 130 | ret = -EEXIST; |
Herbert Xu | 4cc7720 | 2006-08-06 21:16:34 +1000 | [diff] [blame] | 131 | |
Herbert Xu | 2825982 | 2006-08-06 21:23:26 +1000 | [diff] [blame] | 132 | atomic_set(&alg->cra_refcnt, 1); |
Herbert Xu | cce9e06 | 2006-08-21 21:08:13 +1000 | [diff] [blame] | 133 | list_for_each_entry(q, &crypto_alg_list, cra_list) { |
Herbert Xu | 4cc7720 | 2006-08-06 21:16:34 +1000 | [diff] [blame] | 134 | if (q == alg) |
Herbert Xu | cce9e06 | 2006-08-21 21:08:13 +1000 | [diff] [blame] | 135 | goto out; |
Herbert Xu | 6bfd480 | 2006-09-21 11:39:29 +1000 | [diff] [blame^] | 136 | |
| 137 | if (crypto_is_moribund(q)) |
| 138 | continue; |
| 139 | |
| 140 | if (crypto_is_larval(q)) { |
Herbert Xu | 2825982 | 2006-08-06 21:23:26 +1000 | [diff] [blame] | 141 | struct crypto_larval *larval = (void *)q; |
| 142 | |
Herbert Xu | 6bfd480 | 2006-09-21 11:39:29 +1000 | [diff] [blame^] | 143 | if (strcmp(alg->cra_name, q->cra_name) && |
| 144 | strcmp(alg->cra_driver_name, q->cra_name)) |
| 145 | continue; |
| 146 | |
| 147 | if (larval->adult) |
| 148 | continue; |
Herbert Xu | 492e2b6 | 2006-09-21 11:35:17 +1000 | [diff] [blame] | 149 | if ((q->cra_flags ^ alg->cra_flags) & larval->mask) |
| 150 | continue; |
Herbert Xu | 2825982 | 2006-08-06 21:23:26 +1000 | [diff] [blame] | 151 | if (!crypto_mod_get(alg)) |
| 152 | continue; |
Herbert Xu | 6bfd480 | 2006-09-21 11:39:29 +1000 | [diff] [blame^] | 153 | |
Herbert Xu | 2825982 | 2006-08-06 21:23:26 +1000 | [diff] [blame] | 154 | larval->adult = alg; |
| 155 | complete(&larval->completion); |
Herbert Xu | 6bfd480 | 2006-09-21 11:39:29 +1000 | [diff] [blame^] | 156 | continue; |
Herbert Xu | 2825982 | 2006-08-06 21:23:26 +1000 | [diff] [blame] | 157 | } |
Herbert Xu | 6bfd480 | 2006-09-21 11:39:29 +1000 | [diff] [blame^] | 158 | |
| 159 | if (strcmp(alg->cra_name, q->cra_name)) |
| 160 | continue; |
| 161 | |
| 162 | if (strcmp(alg->cra_driver_name, q->cra_driver_name) && |
| 163 | q->cra_priority > alg->cra_priority) |
| 164 | continue; |
| 165 | |
| 166 | crypto_remove_spawns(&q->cra_users, list); |
Herbert Xu | cce9e06 | 2006-08-21 21:08:13 +1000 | [diff] [blame] | 167 | } |
| 168 | |
| 169 | list_add(&alg->cra_list, &crypto_alg_list); |
Herbert Xu | 2825982 | 2006-08-06 21:23:26 +1000 | [diff] [blame] | 170 | |
| 171 | crypto_notify(CRYPTO_MSG_ALG_REGISTER, alg); |
Herbert Xu | 4cc7720 | 2006-08-06 21:16:34 +1000 | [diff] [blame] | 172 | ret = 0; |
Herbert Xu | 2825982 | 2006-08-06 21:23:26 +1000 | [diff] [blame] | 173 | |
Herbert Xu | cce9e06 | 2006-08-21 21:08:13 +1000 | [diff] [blame] | 174 | out: |
Herbert Xu | cce9e06 | 2006-08-21 21:08:13 +1000 | [diff] [blame] | 175 | return ret; |
| 176 | } |
Herbert Xu | 4cc7720 | 2006-08-06 21:16:34 +1000 | [diff] [blame] | 177 | |
Herbert Xu | 6bfd480 | 2006-09-21 11:39:29 +1000 | [diff] [blame^] | 178 | static void crypto_remove_final(struct list_head *list) |
| 179 | { |
| 180 | struct crypto_alg *alg; |
| 181 | struct crypto_alg *n; |
| 182 | |
| 183 | list_for_each_entry_safe(alg, n, list, cra_list) { |
| 184 | list_del_init(&alg->cra_list); |
| 185 | crypto_alg_put(alg); |
| 186 | } |
| 187 | } |
| 188 | |
Herbert Xu | 4cc7720 | 2006-08-06 21:16:34 +1000 | [diff] [blame] | 189 | int crypto_register_alg(struct crypto_alg *alg) |
| 190 | { |
Herbert Xu | 6bfd480 | 2006-09-21 11:39:29 +1000 | [diff] [blame^] | 191 | LIST_HEAD(list); |
Herbert Xu | 4cc7720 | 2006-08-06 21:16:34 +1000 | [diff] [blame] | 192 | int err; |
| 193 | |
| 194 | err = crypto_check_alg(alg); |
| 195 | if (err) |
| 196 | return err; |
| 197 | |
| 198 | down_write(&crypto_alg_sem); |
Herbert Xu | 6bfd480 | 2006-09-21 11:39:29 +1000 | [diff] [blame^] | 199 | err = __crypto_register_alg(alg, &list); |
Herbert Xu | 4cc7720 | 2006-08-06 21:16:34 +1000 | [diff] [blame] | 200 | up_write(&crypto_alg_sem); |
| 201 | |
Herbert Xu | 6bfd480 | 2006-09-21 11:39:29 +1000 | [diff] [blame^] | 202 | crypto_remove_final(&list); |
Herbert Xu | 4cc7720 | 2006-08-06 21:16:34 +1000 | [diff] [blame] | 203 | return err; |
| 204 | } |
Herbert Xu | cce9e06 | 2006-08-21 21:08:13 +1000 | [diff] [blame] | 205 | EXPORT_SYMBOL_GPL(crypto_register_alg); |
| 206 | |
Herbert Xu | 6bfd480 | 2006-09-21 11:39:29 +1000 | [diff] [blame^] | 207 | static int crypto_remove_alg(struct crypto_alg *alg, struct list_head *list) |
| 208 | { |
| 209 | if (unlikely(list_empty(&alg->cra_list))) |
| 210 | return -ENOENT; |
| 211 | |
| 212 | alg->cra_flags |= CRYPTO_ALG_DEAD; |
| 213 | |
| 214 | crypto_notify(CRYPTO_MSG_ALG_UNREGISTER, alg); |
| 215 | list_del_init(&alg->cra_list); |
| 216 | crypto_remove_spawns(&alg->cra_users, list); |
| 217 | |
| 218 | return 0; |
| 219 | } |
| 220 | |
Herbert Xu | cce9e06 | 2006-08-21 21:08:13 +1000 | [diff] [blame] | 221 | int crypto_unregister_alg(struct crypto_alg *alg) |
| 222 | { |
Herbert Xu | 6bfd480 | 2006-09-21 11:39:29 +1000 | [diff] [blame^] | 223 | int ret; |
| 224 | LIST_HEAD(list); |
Herbert Xu | cce9e06 | 2006-08-21 21:08:13 +1000 | [diff] [blame] | 225 | |
| 226 | down_write(&crypto_alg_sem); |
Herbert Xu | 6bfd480 | 2006-09-21 11:39:29 +1000 | [diff] [blame^] | 227 | ret = crypto_remove_alg(alg, &list); |
Herbert Xu | cce9e06 | 2006-08-21 21:08:13 +1000 | [diff] [blame] | 228 | up_write(&crypto_alg_sem); |
| 229 | |
| 230 | if (ret) |
| 231 | return ret; |
| 232 | |
| 233 | BUG_ON(atomic_read(&alg->cra_refcnt) != 1); |
| 234 | if (alg->cra_destroy) |
| 235 | alg->cra_destroy(alg); |
| 236 | |
Herbert Xu | 6bfd480 | 2006-09-21 11:39:29 +1000 | [diff] [blame^] | 237 | crypto_remove_final(&list); |
Herbert Xu | cce9e06 | 2006-08-21 21:08:13 +1000 | [diff] [blame] | 238 | return 0; |
| 239 | } |
| 240 | EXPORT_SYMBOL_GPL(crypto_unregister_alg); |
| 241 | |
Herbert Xu | 4cc7720 | 2006-08-06 21:16:34 +1000 | [diff] [blame] | 242 | int crypto_register_template(struct crypto_template *tmpl) |
| 243 | { |
| 244 | struct crypto_template *q; |
| 245 | int err = -EEXIST; |
| 246 | |
| 247 | down_write(&crypto_alg_sem); |
| 248 | |
| 249 | list_for_each_entry(q, &crypto_template_list, list) { |
| 250 | if (q == tmpl) |
| 251 | goto out; |
| 252 | } |
| 253 | |
| 254 | list_add(&tmpl->list, &crypto_template_list); |
Herbert Xu | 2825982 | 2006-08-06 21:23:26 +1000 | [diff] [blame] | 255 | crypto_notify(CRYPTO_MSG_TMPL_REGISTER, tmpl); |
Herbert Xu | 4cc7720 | 2006-08-06 21:16:34 +1000 | [diff] [blame] | 256 | err = 0; |
| 257 | out: |
| 258 | up_write(&crypto_alg_sem); |
| 259 | return err; |
| 260 | } |
| 261 | EXPORT_SYMBOL_GPL(crypto_register_template); |
| 262 | |
| 263 | void crypto_unregister_template(struct crypto_template *tmpl) |
| 264 | { |
| 265 | struct crypto_instance *inst; |
| 266 | struct hlist_node *p, *n; |
| 267 | struct hlist_head *list; |
Herbert Xu | 6bfd480 | 2006-09-21 11:39:29 +1000 | [diff] [blame^] | 268 | LIST_HEAD(users); |
Herbert Xu | 4cc7720 | 2006-08-06 21:16:34 +1000 | [diff] [blame] | 269 | |
| 270 | down_write(&crypto_alg_sem); |
| 271 | |
| 272 | BUG_ON(list_empty(&tmpl->list)); |
| 273 | list_del_init(&tmpl->list); |
| 274 | |
| 275 | list = &tmpl->instances; |
| 276 | hlist_for_each_entry(inst, p, list, list) { |
Herbert Xu | 6bfd480 | 2006-09-21 11:39:29 +1000 | [diff] [blame^] | 277 | int err = crypto_remove_alg(&inst->alg, &users); |
| 278 | BUG_ON(err); |
Herbert Xu | 4cc7720 | 2006-08-06 21:16:34 +1000 | [diff] [blame] | 279 | } |
| 280 | |
Herbert Xu | 2825982 | 2006-08-06 21:23:26 +1000 | [diff] [blame] | 281 | crypto_notify(CRYPTO_MSG_TMPL_UNREGISTER, tmpl); |
| 282 | |
Herbert Xu | 4cc7720 | 2006-08-06 21:16:34 +1000 | [diff] [blame] | 283 | up_write(&crypto_alg_sem); |
| 284 | |
| 285 | hlist_for_each_entry_safe(inst, p, n, list, list) { |
| 286 | BUG_ON(atomic_read(&inst->alg.cra_refcnt) != 1); |
| 287 | tmpl->free(inst); |
| 288 | } |
Herbert Xu | 6bfd480 | 2006-09-21 11:39:29 +1000 | [diff] [blame^] | 289 | crypto_remove_final(&users); |
Herbert Xu | 4cc7720 | 2006-08-06 21:16:34 +1000 | [diff] [blame] | 290 | } |
| 291 | EXPORT_SYMBOL_GPL(crypto_unregister_template); |
| 292 | |
| 293 | static struct crypto_template *__crypto_lookup_template(const char *name) |
| 294 | { |
| 295 | struct crypto_template *q, *tmpl = NULL; |
| 296 | |
| 297 | down_read(&crypto_alg_sem); |
| 298 | list_for_each_entry(q, &crypto_template_list, list) { |
| 299 | if (strcmp(q->name, name)) |
| 300 | continue; |
| 301 | if (unlikely(!crypto_tmpl_get(q))) |
| 302 | continue; |
| 303 | |
| 304 | tmpl = q; |
| 305 | break; |
| 306 | } |
| 307 | up_read(&crypto_alg_sem); |
| 308 | |
| 309 | return tmpl; |
| 310 | } |
| 311 | |
| 312 | struct crypto_template *crypto_lookup_template(const char *name) |
| 313 | { |
| 314 | return try_then_request_module(__crypto_lookup_template(name), name); |
| 315 | } |
| 316 | EXPORT_SYMBOL_GPL(crypto_lookup_template); |
| 317 | |
| 318 | int crypto_register_instance(struct crypto_template *tmpl, |
| 319 | struct crypto_instance *inst) |
| 320 | { |
Herbert Xu | 6bfd480 | 2006-09-21 11:39:29 +1000 | [diff] [blame^] | 321 | LIST_HEAD(list); |
Herbert Xu | 4cc7720 | 2006-08-06 21:16:34 +1000 | [diff] [blame] | 322 | int err = -EINVAL; |
| 323 | |
| 324 | if (inst->alg.cra_destroy) |
| 325 | goto err; |
| 326 | |
| 327 | err = crypto_check_alg(&inst->alg); |
| 328 | if (err) |
| 329 | goto err; |
| 330 | |
| 331 | inst->alg.cra_module = tmpl->module; |
| 332 | |
| 333 | down_write(&crypto_alg_sem); |
| 334 | |
Herbert Xu | 6bfd480 | 2006-09-21 11:39:29 +1000 | [diff] [blame^] | 335 | err = __crypto_register_alg(&inst->alg, &list); |
Herbert Xu | 4cc7720 | 2006-08-06 21:16:34 +1000 | [diff] [blame] | 336 | if (err) |
| 337 | goto unlock; |
| 338 | |
| 339 | hlist_add_head(&inst->list, &tmpl->instances); |
| 340 | inst->tmpl = tmpl; |
| 341 | |
| 342 | unlock: |
| 343 | up_write(&crypto_alg_sem); |
| 344 | |
Herbert Xu | 6bfd480 | 2006-09-21 11:39:29 +1000 | [diff] [blame^] | 345 | crypto_remove_final(&list); |
| 346 | |
Herbert Xu | 4cc7720 | 2006-08-06 21:16:34 +1000 | [diff] [blame] | 347 | err: |
| 348 | return err; |
| 349 | } |
| 350 | EXPORT_SYMBOL_GPL(crypto_register_instance); |
| 351 | |
Herbert Xu | 6bfd480 | 2006-09-21 11:39:29 +1000 | [diff] [blame^] | 352 | int crypto_init_spawn(struct crypto_spawn *spawn, struct crypto_alg *alg, |
| 353 | struct crypto_instance *inst) |
| 354 | { |
| 355 | int err = -EAGAIN; |
| 356 | |
| 357 | spawn->inst = inst; |
| 358 | |
| 359 | down_write(&crypto_alg_sem); |
| 360 | if (!crypto_is_moribund(alg)) { |
| 361 | list_add(&spawn->list, &alg->cra_users); |
| 362 | spawn->alg = alg; |
| 363 | err = 0; |
| 364 | } |
| 365 | up_write(&crypto_alg_sem); |
| 366 | |
| 367 | return err; |
| 368 | } |
| 369 | EXPORT_SYMBOL_GPL(crypto_init_spawn); |
| 370 | |
| 371 | void crypto_drop_spawn(struct crypto_spawn *spawn) |
| 372 | { |
| 373 | down_write(&crypto_alg_sem); |
| 374 | list_del(&spawn->list); |
| 375 | up_write(&crypto_alg_sem); |
| 376 | } |
| 377 | EXPORT_SYMBOL_GPL(crypto_drop_spawn); |
| 378 | |
| 379 | struct crypto_tfm *crypto_spawn_tfm(struct crypto_spawn *spawn) |
| 380 | { |
| 381 | struct crypto_alg *alg; |
| 382 | struct crypto_alg *alg2; |
| 383 | struct crypto_tfm *tfm; |
| 384 | |
| 385 | down_read(&crypto_alg_sem); |
| 386 | alg = spawn->alg; |
| 387 | alg2 = alg; |
| 388 | if (alg2) |
| 389 | alg2 = crypto_mod_get(alg2); |
| 390 | up_read(&crypto_alg_sem); |
| 391 | |
| 392 | if (!alg2) { |
| 393 | if (alg) |
| 394 | crypto_shoot_alg(alg); |
| 395 | return ERR_PTR(-EAGAIN); |
| 396 | } |
| 397 | |
| 398 | tfm = __crypto_alloc_tfm(alg, 0); |
| 399 | if (IS_ERR(tfm)) |
| 400 | crypto_mod_put(alg); |
| 401 | |
| 402 | return tfm; |
| 403 | } |
| 404 | EXPORT_SYMBOL_GPL(crypto_spawn_tfm); |
| 405 | |
Herbert Xu | 2825982 | 2006-08-06 21:23:26 +1000 | [diff] [blame] | 406 | int crypto_register_notifier(struct notifier_block *nb) |
| 407 | { |
| 408 | return blocking_notifier_chain_register(&crypto_chain, nb); |
| 409 | } |
| 410 | EXPORT_SYMBOL_GPL(crypto_register_notifier); |
| 411 | |
| 412 | int crypto_unregister_notifier(struct notifier_block *nb) |
| 413 | { |
| 414 | return blocking_notifier_chain_unregister(&crypto_chain, nb); |
| 415 | } |
| 416 | EXPORT_SYMBOL_GPL(crypto_unregister_notifier); |
| 417 | |
Herbert Xu | cce9e06 | 2006-08-21 21:08:13 +1000 | [diff] [blame] | 418 | static int __init crypto_algapi_init(void) |
| 419 | { |
| 420 | crypto_init_proc(); |
| 421 | return 0; |
| 422 | } |
| 423 | |
| 424 | static void __exit crypto_algapi_exit(void) |
| 425 | { |
| 426 | crypto_exit_proc(); |
| 427 | } |
| 428 | |
| 429 | module_init(crypto_algapi_init); |
| 430 | module_exit(crypto_algapi_exit); |
| 431 | |
| 432 | MODULE_LICENSE("GPL"); |
| 433 | MODULE_DESCRIPTION("Cryptographic algorithms API"); |