2007-04-16 14:49:20 +04:00
/*
* Software async crypto daemon .
*
* Copyright ( c ) 2006 Herbert Xu < herbert @ gondor . apana . org . au >
*
* This program is free software ; you can redistribute it and / or modify it
* under the terms of the GNU General Public License as published by the Free
* Software Foundation ; either version 2 of the License , or ( at your option )
* any later version .
*
*/
# include <crypto/algapi.h>
2008-07-10 12:01:22 +04:00
# include <crypto/internal/hash.h>
2009-01-18 08:19:46 +03:00
# include <crypto/cryptd.h>
2009-02-19 09:42:19 +03:00
# include <crypto/crypto_wq.h>
2007-04-16 14:49:20 +04:00
# include <linux/err.h>
# include <linux/init.h>
# include <linux/kernel.h>
# include <linux/list.h>
# include <linux/module.h>
# include <linux/scatterlist.h>
# include <linux/sched.h>
# include <linux/slab.h>
2009-02-19 09:42:19 +03:00
# define CRYPTD_MAX_CPU_QLEN 100
2007-04-16 14:49:20 +04:00
2009-02-19 09:42:19 +03:00
struct cryptd_cpu_queue {
2007-04-16 14:49:20 +04:00
struct crypto_queue queue ;
2009-02-19 09:42:19 +03:00
struct work_struct work ;
} ;
struct cryptd_queue {
struct cryptd_cpu_queue * cpu_queue ;
2007-04-16 14:49:20 +04:00
} ;
struct cryptd_instance_ctx {
struct crypto_spawn spawn ;
2009-02-19 09:42:19 +03:00
struct cryptd_queue * queue ;
2007-04-16 14:49:20 +04:00
} ;
2009-07-12 17:38:59 +04:00
struct hashd_instance_ctx {
struct crypto_shash_spawn spawn ;
struct cryptd_queue * queue ;
} ;
2007-04-16 14:49:20 +04:00
struct cryptd_blkcipher_ctx {
struct crypto_blkcipher * child ;
} ;
struct cryptd_blkcipher_request_ctx {
crypto_completion_t complete ;
} ;
2008-05-14 17:23:00 +04:00
struct cryptd_hash_ctx {
2009-07-12 17:38:59 +04:00
struct crypto_shash * child ;
2008-05-14 17:23:00 +04:00
} ;
struct cryptd_hash_request_ctx {
crypto_completion_t complete ;
2009-07-12 17:38:59 +04:00
struct shash_desc desc ;
2008-05-14 17:23:00 +04:00
} ;
2007-04-16 14:49:20 +04:00
2009-02-19 09:42:19 +03:00
static void cryptd_queue_worker ( struct work_struct * work ) ;
static int cryptd_init_queue ( struct cryptd_queue * queue ,
unsigned int max_cpu_qlen )
{
int cpu ;
struct cryptd_cpu_queue * cpu_queue ;
queue - > cpu_queue = alloc_percpu ( struct cryptd_cpu_queue ) ;
if ( ! queue - > cpu_queue )
return - ENOMEM ;
for_each_possible_cpu ( cpu ) {
cpu_queue = per_cpu_ptr ( queue - > cpu_queue , cpu ) ;
crypto_init_queue ( & cpu_queue - > queue , max_cpu_qlen ) ;
INIT_WORK ( & cpu_queue - > work , cryptd_queue_worker ) ;
}
return 0 ;
}
static void cryptd_fini_queue ( struct cryptd_queue * queue )
{
int cpu ;
struct cryptd_cpu_queue * cpu_queue ;
for_each_possible_cpu ( cpu ) {
cpu_queue = per_cpu_ptr ( queue - > cpu_queue , cpu ) ;
BUG_ON ( cpu_queue - > queue . qlen ) ;
}
free_percpu ( queue - > cpu_queue ) ;
}
static int cryptd_enqueue_request ( struct cryptd_queue * queue ,
struct crypto_async_request * request )
{
int cpu , err ;
struct cryptd_cpu_queue * cpu_queue ;
cpu = get_cpu ( ) ;
cpu_queue = per_cpu_ptr ( queue - > cpu_queue , cpu ) ;
err = crypto_enqueue_request ( & cpu_queue - > queue , request ) ;
queue_work_on ( cpu , kcrypto_wq , & cpu_queue - > work ) ;
put_cpu ( ) ;
return err ;
}
/* Called in workqueue context, do one real cryption work (via
* req - > complete ) and reschedule itself if there are more work to
* do . */
static void cryptd_queue_worker ( struct work_struct * work )
{
struct cryptd_cpu_queue * cpu_queue ;
struct crypto_async_request * req , * backlog ;
cpu_queue = container_of ( work , struct cryptd_cpu_queue , work ) ;
/* Only handle one request at a time to avoid hogging crypto
* workqueue . preempt_disable / enable is used to prevent
* being preempted by cryptd_enqueue_request ( ) */
preempt_disable ( ) ;
backlog = crypto_get_backlog ( & cpu_queue - > queue ) ;
req = crypto_dequeue_request ( & cpu_queue - > queue ) ;
preempt_enable ( ) ;
if ( ! req )
return ;
if ( backlog )
backlog - > complete ( backlog , - EINPROGRESS ) ;
req - > complete ( req , 0 ) ;
if ( cpu_queue - > queue . qlen )
queue_work ( kcrypto_wq , & cpu_queue - > work ) ;
}
static inline struct cryptd_queue * cryptd_get_queue ( struct crypto_tfm * tfm )
2007-04-16 14:49:20 +04:00
{
struct crypto_instance * inst = crypto_tfm_alg_instance ( tfm ) ;
struct cryptd_instance_ctx * ictx = crypto_instance_ctx ( inst ) ;
2009-02-19 09:42:19 +03:00
return ictx - > queue ;
2007-04-16 14:49:20 +04:00
}
static int cryptd_blkcipher_setkey ( struct crypto_ablkcipher * parent ,
const u8 * key , unsigned int keylen )
{
struct cryptd_blkcipher_ctx * ctx = crypto_ablkcipher_ctx ( parent ) ;
struct crypto_blkcipher * child = ctx - > child ;
int err ;
crypto_blkcipher_clear_flags ( child , CRYPTO_TFM_REQ_MASK ) ;
crypto_blkcipher_set_flags ( child , crypto_ablkcipher_get_flags ( parent ) &
CRYPTO_TFM_REQ_MASK ) ;
err = crypto_blkcipher_setkey ( child , key , keylen ) ;
crypto_ablkcipher_set_flags ( parent , crypto_blkcipher_get_flags ( child ) &
CRYPTO_TFM_RES_MASK ) ;
return err ;
}
static void cryptd_blkcipher_crypt ( struct ablkcipher_request * req ,
struct crypto_blkcipher * child ,
int err ,
int ( * crypt ) ( struct blkcipher_desc * desc ,
struct scatterlist * dst ,
struct scatterlist * src ,
unsigned int len ) )
{
struct cryptd_blkcipher_request_ctx * rctx ;
struct blkcipher_desc desc ;
rctx = ablkcipher_request_ctx ( req ) ;
2008-05-07 17:10:13 +04:00
if ( unlikely ( err = = - EINPROGRESS ) )
goto out ;
2007-04-16 14:49:20 +04:00
desc . tfm = child ;
desc . info = req - > info ;
desc . flags = CRYPTO_TFM_REQ_MAY_SLEEP ;
err = crypt ( & desc , req - > dst , req - > src , req - > nbytes ) ;
req - > base . complete = rctx - > complete ;
2008-05-07 17:10:13 +04:00
out :
2007-04-16 14:49:20 +04:00
local_bh_disable ( ) ;
2008-05-07 17:10:13 +04:00
rctx - > complete ( & req - > base , err ) ;
2007-04-16 14:49:20 +04:00
local_bh_enable ( ) ;
}
static void cryptd_blkcipher_encrypt ( struct crypto_async_request * req , int err )
{
struct cryptd_blkcipher_ctx * ctx = crypto_tfm_ctx ( req - > tfm ) ;
struct crypto_blkcipher * child = ctx - > child ;
cryptd_blkcipher_crypt ( ablkcipher_request_cast ( req ) , child , err ,
crypto_blkcipher_crt ( child ) - > encrypt ) ;
}
static void cryptd_blkcipher_decrypt ( struct crypto_async_request * req , int err )
{
struct cryptd_blkcipher_ctx * ctx = crypto_tfm_ctx ( req - > tfm ) ;
struct crypto_blkcipher * child = ctx - > child ;
cryptd_blkcipher_crypt ( ablkcipher_request_cast ( req ) , child , err ,
crypto_blkcipher_crt ( child ) - > decrypt ) ;
}
static int cryptd_blkcipher_enqueue ( struct ablkcipher_request * req ,
crypto_completion_t complete )
{
struct cryptd_blkcipher_request_ctx * rctx = ablkcipher_request_ctx ( req ) ;
struct crypto_ablkcipher * tfm = crypto_ablkcipher_reqtfm ( req ) ;
2009-02-19 09:42:19 +03:00
struct cryptd_queue * queue ;
2007-04-16 14:49:20 +04:00
2009-02-19 09:42:19 +03:00
queue = cryptd_get_queue ( crypto_ablkcipher_tfm ( tfm ) ) ;
2007-04-16 14:49:20 +04:00
rctx - > complete = req - > base . complete ;
req - > base . complete = complete ;
2009-02-19 09:42:19 +03:00
return cryptd_enqueue_request ( queue , & req - > base ) ;
2007-04-16 14:49:20 +04:00
}
static int cryptd_blkcipher_encrypt_enqueue ( struct ablkcipher_request * req )
{
return cryptd_blkcipher_enqueue ( req , cryptd_blkcipher_encrypt ) ;
}
static int cryptd_blkcipher_decrypt_enqueue ( struct ablkcipher_request * req )
{
return cryptd_blkcipher_enqueue ( req , cryptd_blkcipher_decrypt ) ;
}
static int cryptd_blkcipher_init_tfm ( struct crypto_tfm * tfm )
{
struct crypto_instance * inst = crypto_tfm_alg_instance ( tfm ) ;
struct cryptd_instance_ctx * ictx = crypto_instance_ctx ( inst ) ;
struct crypto_spawn * spawn = & ictx - > spawn ;
struct cryptd_blkcipher_ctx * ctx = crypto_tfm_ctx ( tfm ) ;
struct crypto_blkcipher * cipher ;
cipher = crypto_spawn_blkcipher ( spawn ) ;
if ( IS_ERR ( cipher ) )
return PTR_ERR ( cipher ) ;
ctx - > child = cipher ;
tfm - > crt_ablkcipher . reqsize =
sizeof ( struct cryptd_blkcipher_request_ctx ) ;
return 0 ;
}
static void cryptd_blkcipher_exit_tfm ( struct crypto_tfm * tfm )
{
struct cryptd_blkcipher_ctx * ctx = crypto_tfm_ctx ( tfm ) ;
crypto_free_blkcipher ( ctx - > child ) ;
}
static struct crypto_instance * cryptd_alloc_instance ( struct crypto_alg * alg ,
2009-07-12 17:38:59 +04:00
unsigned int tail )
2007-04-16 14:49:20 +04:00
{
struct crypto_instance * inst ;
int err ;
2009-07-12 17:38:59 +04:00
inst = kzalloc ( sizeof ( * inst ) + tail , GFP_KERNEL ) ;
2008-04-29 20:27:14 +04:00
if ( ! inst ) {
inst = ERR_PTR ( - ENOMEM ) ;
2007-04-16 14:49:20 +04:00
goto out ;
2008-04-29 20:27:14 +04:00
}
2007-04-16 14:49:20 +04:00
err = - ENAMETOOLONG ;
if ( snprintf ( inst - > alg . cra_driver_name , CRYPTO_MAX_ALG_NAME ,
" cryptd(%s) " , alg - > cra_driver_name ) > = CRYPTO_MAX_ALG_NAME )
goto out_free_inst ;
memcpy ( inst - > alg . cra_name , alg - > cra_name , CRYPTO_MAX_ALG_NAME ) ;
inst - > alg . cra_priority = alg - > cra_priority + 50 ;
inst - > alg . cra_blocksize = alg - > cra_blocksize ;
inst - > alg . cra_alignmask = alg - > cra_alignmask ;
out :
return inst ;
out_free_inst :
kfree ( inst ) ;
inst = ERR_PTR ( err ) ;
goto out ;
}
static struct crypto_instance * cryptd_alloc_blkcipher (
2009-02-19 09:42:19 +03:00
struct rtattr * * tb , struct cryptd_queue * queue )
2007-04-16 14:49:20 +04:00
{
2009-07-12 17:38:59 +04:00
struct cryptd_instance_ctx * ctx ;
2007-04-16 14:49:20 +04:00
struct crypto_instance * inst ;
struct crypto_alg * alg ;
2009-07-12 17:38:59 +04:00
int err ;
2007-04-16 14:49:20 +04:00
alg = crypto_get_attr_alg ( tb , CRYPTO_ALG_TYPE_BLKCIPHER ,
2007-11-15 17:36:07 +03:00
CRYPTO_ALG_TYPE_MASK ) ;
2007-04-16 14:49:20 +04:00
if ( IS_ERR ( alg ) )
2008-02-07 11:15:26 +03:00
return ERR_CAST ( alg ) ;
2007-04-16 14:49:20 +04:00
2009-07-12 17:38:59 +04:00
inst = cryptd_alloc_instance ( alg , sizeof ( * ctx ) ) ;
2007-04-16 14:49:20 +04:00
if ( IS_ERR ( inst ) )
goto out_put_alg ;
2009-07-12 17:38:59 +04:00
ctx = crypto_instance_ctx ( inst ) ;
ctx - > queue = queue ;
err = crypto_init_spawn ( & ctx - > spawn , alg , inst ,
CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_ASYNC ) ;
if ( err )
goto out_free_inst ;
2007-11-15 17:36:07 +03:00
inst - > alg . cra_flags = CRYPTO_ALG_TYPE_ABLKCIPHER | CRYPTO_ALG_ASYNC ;
2007-04-16 14:49:20 +04:00
inst - > alg . cra_type = & crypto_ablkcipher_type ;
inst - > alg . cra_ablkcipher . ivsize = alg - > cra_blkcipher . ivsize ;
inst - > alg . cra_ablkcipher . min_keysize = alg - > cra_blkcipher . min_keysize ;
inst - > alg . cra_ablkcipher . max_keysize = alg - > cra_blkcipher . max_keysize ;
2007-11-27 16:15:31 +03:00
inst - > alg . cra_ablkcipher . geniv = alg - > cra_blkcipher . geniv ;
2007-04-16 14:49:20 +04:00
inst - > alg . cra_ctxsize = sizeof ( struct cryptd_blkcipher_ctx ) ;
inst - > alg . cra_init = cryptd_blkcipher_init_tfm ;
inst - > alg . cra_exit = cryptd_blkcipher_exit_tfm ;
inst - > alg . cra_ablkcipher . setkey = cryptd_blkcipher_setkey ;
inst - > alg . cra_ablkcipher . encrypt = cryptd_blkcipher_encrypt_enqueue ;
inst - > alg . cra_ablkcipher . decrypt = cryptd_blkcipher_decrypt_enqueue ;
out_put_alg :
crypto_mod_put ( alg ) ;
return inst ;
2009-07-12 17:38:59 +04:00
out_free_inst :
kfree ( inst ) ;
inst = ERR_PTR ( err ) ;
goto out_put_alg ;
2007-04-16 14:49:20 +04:00
}
2008-05-14 17:23:00 +04:00
static int cryptd_hash_init_tfm ( struct crypto_tfm * tfm )
{
struct crypto_instance * inst = crypto_tfm_alg_instance ( tfm ) ;
2009-07-12 17:38:59 +04:00
struct hashd_instance_ctx * ictx = crypto_instance_ctx ( inst ) ;
struct crypto_shash_spawn * spawn = & ictx - > spawn ;
2008-05-14 17:23:00 +04:00
struct cryptd_hash_ctx * ctx = crypto_tfm_ctx ( tfm ) ;
2009-07-12 17:38:59 +04:00
struct crypto_shash * hash ;
2008-05-14 17:23:00 +04:00
2009-07-12 17:38:59 +04:00
hash = crypto_spawn_shash ( spawn ) ;
if ( IS_ERR ( hash ) )
return PTR_ERR ( hash ) ;
2008-05-14 17:23:00 +04:00
2009-07-12 17:38:59 +04:00
ctx - > child = hash ;
tfm - > crt_ahash . reqsize = sizeof ( struct cryptd_hash_request_ctx ) +
crypto_shash_descsize ( hash ) ;
2008-05-14 17:23:00 +04:00
return 0 ;
}
static void cryptd_hash_exit_tfm ( struct crypto_tfm * tfm )
{
struct cryptd_hash_ctx * ctx = crypto_tfm_ctx ( tfm ) ;
2009-07-12 17:38:59 +04:00
crypto_free_shash ( ctx - > child ) ;
2008-05-14 17:23:00 +04:00
}
static int cryptd_hash_setkey ( struct crypto_ahash * parent ,
const u8 * key , unsigned int keylen )
{
struct cryptd_hash_ctx * ctx = crypto_ahash_ctx ( parent ) ;
2009-07-12 17:38:59 +04:00
struct crypto_shash * child = ctx - > child ;
2008-05-14 17:23:00 +04:00
int err ;
2009-07-12 17:38:59 +04:00
crypto_shash_clear_flags ( child , CRYPTO_TFM_REQ_MASK ) ;
crypto_shash_set_flags ( child , crypto_ahash_get_flags ( parent ) &
CRYPTO_TFM_REQ_MASK ) ;
err = crypto_shash_setkey ( child , key , keylen ) ;
crypto_ahash_set_flags ( parent , crypto_shash_get_flags ( child ) &
CRYPTO_TFM_RES_MASK ) ;
2008-05-14 17:23:00 +04:00
return err ;
}
static int cryptd_hash_enqueue ( struct ahash_request * req ,
crypto_completion_t complete )
{
struct cryptd_hash_request_ctx * rctx = ahash_request_ctx ( req ) ;
struct crypto_ahash * tfm = crypto_ahash_reqtfm ( req ) ;
2009-02-19 09:42:19 +03:00
struct cryptd_queue * queue =
cryptd_get_queue ( crypto_ahash_tfm ( tfm ) ) ;
2008-05-14 17:23:00 +04:00
rctx - > complete = req - > base . complete ;
req - > base . complete = complete ;
2009-02-19 09:42:19 +03:00
return cryptd_enqueue_request ( queue , & req - > base ) ;
2008-05-14 17:23:00 +04:00
}
static void cryptd_hash_init ( struct crypto_async_request * req_async , int err )
{
2009-07-12 17:38:59 +04:00
struct cryptd_hash_ctx * ctx = crypto_tfm_ctx ( req_async - > tfm ) ;
struct crypto_shash * child = ctx - > child ;
struct ahash_request * req = ahash_request_cast ( req_async ) ;
struct cryptd_hash_request_ctx * rctx = ahash_request_ctx ( req ) ;
struct shash_desc * desc = & rctx - > desc ;
2008-05-14 17:23:00 +04:00
if ( unlikely ( err = = - EINPROGRESS ) )
goto out ;
2009-07-12 17:38:59 +04:00
desc - > tfm = child ;
desc - > flags = CRYPTO_TFM_REQ_MAY_SLEEP ;
2008-05-14 17:23:00 +04:00
2009-07-12 17:38:59 +04:00
err = crypto_shash_init ( desc ) ;
2008-05-14 17:23:00 +04:00
req - > base . complete = rctx - > complete ;
out :
local_bh_disable ( ) ;
rctx - > complete ( & req - > base , err ) ;
local_bh_enable ( ) ;
}
static int cryptd_hash_init_enqueue ( struct ahash_request * req )
{
return cryptd_hash_enqueue ( req , cryptd_hash_init ) ;
}
static void cryptd_hash_update ( struct crypto_async_request * req_async , int err )
{
2009-07-12 17:38:59 +04:00
struct ahash_request * req = ahash_request_cast ( req_async ) ;
2008-05-14 17:23:00 +04:00
struct cryptd_hash_request_ctx * rctx ;
rctx = ahash_request_ctx ( req ) ;
if ( unlikely ( err = = - EINPROGRESS ) )
goto out ;
2009-07-12 17:38:59 +04:00
err = shash_ahash_update ( req , & rctx - > desc ) ;
2008-05-14 17:23:00 +04:00
req - > base . complete = rctx - > complete ;
out :
local_bh_disable ( ) ;
rctx - > complete ( & req - > base , err ) ;
local_bh_enable ( ) ;
}
static int cryptd_hash_update_enqueue ( struct ahash_request * req )
{
return cryptd_hash_enqueue ( req , cryptd_hash_update ) ;
}
static void cryptd_hash_final ( struct crypto_async_request * req_async , int err )
{
2009-07-12 17:38:59 +04:00
struct ahash_request * req = ahash_request_cast ( req_async ) ;
struct cryptd_hash_request_ctx * rctx = ahash_request_ctx ( req ) ;
2008-05-14 17:23:00 +04:00
if ( unlikely ( err = = - EINPROGRESS ) )
goto out ;
2009-07-12 17:38:59 +04:00
err = crypto_shash_final ( & rctx - > desc , req - > result ) ;
2008-05-14 17:23:00 +04:00
req - > base . complete = rctx - > complete ;
out :
local_bh_disable ( ) ;
rctx - > complete ( & req - > base , err ) ;
local_bh_enable ( ) ;
}
static int cryptd_hash_final_enqueue ( struct ahash_request * req )
{
return cryptd_hash_enqueue ( req , cryptd_hash_final ) ;
}
static void cryptd_hash_digest ( struct crypto_async_request * req_async , int err )
{
2009-07-12 17:38:59 +04:00
struct cryptd_hash_ctx * ctx = crypto_tfm_ctx ( req_async - > tfm ) ;
struct crypto_shash * child = ctx - > child ;
struct ahash_request * req = ahash_request_cast ( req_async ) ;
struct cryptd_hash_request_ctx * rctx = ahash_request_ctx ( req ) ;
struct shash_desc * desc = & rctx - > desc ;
2008-05-14 17:23:00 +04:00
if ( unlikely ( err = = - EINPROGRESS ) )
goto out ;
2009-07-12 17:38:59 +04:00
desc - > tfm = child ;
desc - > flags = CRYPTO_TFM_REQ_MAY_SLEEP ;
2008-05-14 17:23:00 +04:00
2009-07-12 17:38:59 +04:00
err = shash_ahash_digest ( req , desc ) ;
2008-05-14 17:23:00 +04:00
req - > base . complete = rctx - > complete ;
out :
local_bh_disable ( ) ;
rctx - > complete ( & req - > base , err ) ;
local_bh_enable ( ) ;
}
static int cryptd_hash_digest_enqueue ( struct ahash_request * req )
{
return cryptd_hash_enqueue ( req , cryptd_hash_digest ) ;
}
static struct crypto_instance * cryptd_alloc_hash (
2009-02-19 09:42:19 +03:00
struct rtattr * * tb , struct cryptd_queue * queue )
2008-05-14 17:23:00 +04:00
{
2009-07-12 17:38:59 +04:00
struct hashd_instance_ctx * ctx ;
2008-05-14 17:23:00 +04:00
struct crypto_instance * inst ;
2009-07-12 17:38:59 +04:00
struct shash_alg * salg ;
2008-05-14 17:23:00 +04:00
struct crypto_alg * alg ;
2009-07-12 17:38:59 +04:00
int err ;
2008-05-14 17:23:00 +04:00
2009-07-12 17:38:59 +04:00
salg = shash_attr_alg ( tb [ 1 ] , 0 , 0 ) ;
if ( IS_ERR ( salg ) )
return ERR_CAST ( salg ) ;
2008-05-14 17:23:00 +04:00
2009-07-12 17:38:59 +04:00
alg = & salg - > base ;
inst = cryptd_alloc_instance ( alg , sizeof ( * ctx ) ) ;
2008-05-14 17:23:00 +04:00
if ( IS_ERR ( inst ) )
goto out_put_alg ;
2009-07-12 17:38:59 +04:00
ctx = crypto_instance_ctx ( inst ) ;
ctx - > queue = queue ;
err = crypto_init_shash_spawn ( & ctx - > spawn , salg , inst ) ;
if ( err )
goto out_free_inst ;
2008-05-14 17:23:00 +04:00
inst - > alg . cra_flags = CRYPTO_ALG_TYPE_AHASH | CRYPTO_ALG_ASYNC ;
inst - > alg . cra_type = & crypto_ahash_type ;
2009-07-12 17:38:59 +04:00
inst - > alg . cra_ahash . digestsize = salg - > digestsize ;
2008-05-14 17:23:00 +04:00
inst - > alg . cra_ctxsize = sizeof ( struct cryptd_hash_ctx ) ;
inst - > alg . cra_init = cryptd_hash_init_tfm ;
inst - > alg . cra_exit = cryptd_hash_exit_tfm ;
inst - > alg . cra_ahash . init = cryptd_hash_init_enqueue ;
inst - > alg . cra_ahash . update = cryptd_hash_update_enqueue ;
inst - > alg . cra_ahash . final = cryptd_hash_final_enqueue ;
inst - > alg . cra_ahash . setkey = cryptd_hash_setkey ;
inst - > alg . cra_ahash . digest = cryptd_hash_digest_enqueue ;
out_put_alg :
crypto_mod_put ( alg ) ;
return inst ;
2009-07-12 17:38:59 +04:00
out_free_inst :
kfree ( inst ) ;
inst = ERR_PTR ( err ) ;
goto out_put_alg ;
2008-05-14 17:23:00 +04:00
}
2009-02-19 09:42:19 +03:00
static struct cryptd_queue queue ;
2007-04-16 14:49:20 +04:00
static struct crypto_instance * cryptd_alloc ( struct rtattr * * tb )
{
struct crypto_attr_type * algt ;
algt = crypto_get_attr_type ( tb ) ;
if ( IS_ERR ( algt ) )
2008-02-07 11:15:26 +03:00
return ERR_CAST ( algt ) ;
2007-04-16 14:49:20 +04:00
switch ( algt - > type & algt - > mask & CRYPTO_ALG_TYPE_MASK ) {
case CRYPTO_ALG_TYPE_BLKCIPHER :
2009-02-19 09:42:19 +03:00
return cryptd_alloc_blkcipher ( tb , & queue ) ;
2008-05-14 17:23:00 +04:00
case CRYPTO_ALG_TYPE_DIGEST :
2009-02-19 09:42:19 +03:00
return cryptd_alloc_hash ( tb , & queue ) ;
2007-04-16 14:49:20 +04:00
}
return ERR_PTR ( - EINVAL ) ;
}
static void cryptd_free ( struct crypto_instance * inst )
{
struct cryptd_instance_ctx * ctx = crypto_instance_ctx ( inst ) ;
crypto_drop_spawn ( & ctx - > spawn ) ;
kfree ( inst ) ;
}
static struct crypto_template cryptd_tmpl = {
. name = " cryptd " ,
. alloc = cryptd_alloc ,
. free = cryptd_free ,
. module = THIS_MODULE ,
} ;
2009-01-18 08:19:46 +03:00
struct cryptd_ablkcipher * cryptd_alloc_ablkcipher ( const char * alg_name ,
u32 type , u32 mask )
{
char cryptd_alg_name [ CRYPTO_MAX_ALG_NAME ] ;
2009-03-29 11:33:53 +04:00
struct crypto_tfm * tfm ;
2009-01-18 08:19:46 +03:00
if ( snprintf ( cryptd_alg_name , CRYPTO_MAX_ALG_NAME ,
" cryptd(%s) " , alg_name ) > = CRYPTO_MAX_ALG_NAME )
return ERR_PTR ( - EINVAL ) ;
2009-03-29 11:33:53 +04:00
type & = ~ ( CRYPTO_ALG_TYPE_MASK | CRYPTO_ALG_GENIV ) ;
type | = CRYPTO_ALG_TYPE_BLKCIPHER ;
mask & = ~ CRYPTO_ALG_TYPE_MASK ;
mask | = ( CRYPTO_ALG_GENIV | CRYPTO_ALG_TYPE_BLKCIPHER_MASK ) ;
tfm = crypto_alloc_base ( cryptd_alg_name , type , mask ) ;
2009-01-18 08:19:46 +03:00
if ( IS_ERR ( tfm ) )
return ERR_CAST ( tfm ) ;
2009-03-29 11:33:53 +04:00
if ( tfm - > __crt_alg - > cra_module ! = THIS_MODULE ) {
crypto_free_tfm ( tfm ) ;
2009-01-18 08:19:46 +03:00
return ERR_PTR ( - EINVAL ) ;
}
2009-03-29 11:33:53 +04:00
return __cryptd_ablkcipher_cast ( __crypto_ablkcipher_cast ( tfm ) ) ;
2009-01-18 08:19:46 +03:00
}
EXPORT_SYMBOL_GPL ( cryptd_alloc_ablkcipher ) ;
struct crypto_blkcipher * cryptd_ablkcipher_child ( struct cryptd_ablkcipher * tfm )
{
struct cryptd_blkcipher_ctx * ctx = crypto_ablkcipher_ctx ( & tfm - > base ) ;
return ctx - > child ;
}
EXPORT_SYMBOL_GPL ( cryptd_ablkcipher_child ) ;
void cryptd_free_ablkcipher ( struct cryptd_ablkcipher * tfm )
{
crypto_free_ablkcipher ( & tfm - > base ) ;
}
EXPORT_SYMBOL_GPL ( cryptd_free_ablkcipher ) ;
2007-04-16 14:49:20 +04:00
static int __init cryptd_init ( void )
{
int err ;
2009-02-19 09:42:19 +03:00
err = cryptd_init_queue ( & queue , CRYPTD_MAX_CPU_QLEN ) ;
2007-04-16 14:49:20 +04:00
if ( err )
return err ;
err = crypto_register_template ( & cryptd_tmpl ) ;
if ( err )
2009-02-19 09:42:19 +03:00
cryptd_fini_queue ( & queue ) ;
2007-04-16 14:49:20 +04:00
return err ;
}
static void __exit cryptd_exit ( void )
{
2009-02-19 09:42:19 +03:00
cryptd_fini_queue ( & queue ) ;
2007-04-16 14:49:20 +04:00
crypto_unregister_template ( & cryptd_tmpl ) ;
}
module_init ( cryptd_init ) ;
module_exit ( cryptd_exit ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_DESCRIPTION ( " Software async crypto daemon " ) ;