2006-09-21 05:31:44 +04:00
/*
* Create default crypto algorithm instances .
*
* 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 .
*
*/
2009-02-18 16:41:29 +03:00
# include <crypto/internal/aead.h>
2006-09-21 05:31:44 +04:00
# include <linux/ctype.h>
# include <linux/err.h>
# include <linux/init.h>
2007-03-29 11:32:59 +04:00
# include <linux/kthread.h>
2006-09-21 05:31:44 +04:00
# include <linux/module.h>
# include <linux/notifier.h>
# include <linux/rtnetlink.h>
2006-09-21 05:39:29 +04:00
# include <linux/sched.h>
2006-09-21 05:31:44 +04:00
# include <linux/string.h>
# include "internal.h"
struct cryptomgr_param {
2007-08-29 15:27:26 +04:00
struct rtattr * tb [ CRYPTO_MAX_ATTRS + 2 ] ;
2007-01-01 10:37:02 +03:00
struct {
struct rtattr attr ;
struct crypto_attr_type data ;
} type ;
2007-08-29 15:27:26 +04:00
union {
2006-09-21 05:31:44 +04:00
struct rtattr attr ;
2007-08-29 15:27:26 +04:00
struct {
struct rtattr attr ;
struct crypto_attr_alg data ;
} alg ;
struct {
struct rtattr attr ;
struct crypto_attr_u32 data ;
} nu32 ;
} attrs [ CRYPTO_MAX_ATTRS ] ;
char larval [ CRYPTO_MAX_ALG_NAME ] ;
2006-09-21 05:31:44 +04:00
char template [ CRYPTO_MAX_ALG_NAME ] ;
2008-08-03 17:15:23 +04:00
u32 otype ;
u32 omask ;
} ;
struct crypto_test_param {
char driver [ CRYPTO_MAX_ALG_NAME ] ;
char alg [ CRYPTO_MAX_ALG_NAME ] ;
u32 type ;
2006-09-21 05:31:44 +04:00
} ;
2007-03-29 11:32:59 +04:00
static int cryptomgr_probe ( void * data )
2006-09-21 05:31:44 +04:00
{
2007-03-29 11:32:59 +04:00
struct cryptomgr_param * param = data ;
2006-09-21 05:31:44 +04:00
struct crypto_template * tmpl ;
struct crypto_instance * inst ;
2006-09-21 05:39:29 +04:00
int err ;
2006-09-21 05:31:44 +04:00
tmpl = crypto_lookup_template ( param - > template ) ;
if ( ! tmpl )
goto err ;
2006-09-21 05:39:29 +04:00
do {
2009-07-07 08:30:33 +04:00
if ( tmpl - > create ) {
err = tmpl - > create ( tmpl , param - > tb ) ;
continue ;
}
2007-01-01 10:37:02 +03:00
inst = tmpl - > alloc ( param - > tb ) ;
2006-09-21 05:39:29 +04:00
if ( IS_ERR ( inst ) )
err = PTR_ERR ( inst ) ;
else if ( ( err = crypto_register_instance ( tmpl , inst ) ) )
tmpl - > free ( inst ) ;
} while ( err = = - EAGAIN & & ! signal_pending ( current ) ) ;
2006-09-21 05:31:44 +04:00
crypto_tmpl_put ( tmpl ) ;
2006-09-21 05:39:29 +04:00
if ( err )
goto err ;
2006-09-21 05:31:44 +04:00
out :
kfree ( param ) ;
2007-03-29 11:32:59 +04:00
module_put_and_exit ( 0 ) ;
2006-09-21 05:31:44 +04:00
err :
2008-08-03 17:15:23 +04:00
crypto_larval_error ( param - > larval , param - > otype , param - > omask ) ;
2006-09-21 05:31:44 +04:00
goto out ;
}
static int cryptomgr_schedule_probe ( struct crypto_larval * larval )
{
2007-05-09 07:04:39 +04:00
struct task_struct * thread ;
2006-09-21 05:31:44 +04:00
struct cryptomgr_param * param ;
const char * name = larval - > alg . cra_name ;
const char * p ;
unsigned int len ;
2007-08-29 15:27:26 +04:00
int i ;
2006-09-21 05:31:44 +04:00
2007-03-29 11:32:59 +04:00
if ( ! try_module_get ( THIS_MODULE ) )
goto err ;
2007-01-01 10:37:02 +03:00
param = kzalloc ( sizeof ( * param ) , GFP_KERNEL ) ;
2006-09-21 05:31:44 +04:00
if ( ! param )
2007-03-29 11:32:59 +04:00
goto err_put_module ;
2006-09-21 05:31:44 +04:00
for ( p = name ; isalnum ( * p ) | | * p = = ' - ' | | * p = = ' _ ' ; p + + )
;
len = p - name ;
if ( ! len | | * p ! = ' ( ' )
goto err_free_param ;
memcpy ( param - > template , name , len ) ;
2007-08-29 15:27:26 +04:00
i = 0 ;
for ( ; ; ) {
int notnum = 0 ;
2006-09-21 05:31:44 +04:00
2007-08-29 15:27:26 +04:00
name = + + p ;
len = 0 ;
for ( ; isalnum ( * p ) | | * p = = ' - ' | | * p = = ' _ ' ; p + + )
notnum | = ! isdigit ( * p ) ;
if ( * p = = ' ( ' ) {
int recursion = 0 ;
for ( ; ; ) {
if ( ! * + + p )
goto err_free_param ;
if ( * p = = ' ( ' )
recursion + + ;
else if ( * p = = ' ) ' & & ! recursion - - )
break ;
}
notnum = 1 ;
2007-09-28 05:06:11 +04:00
p + + ;
2007-08-29 15:27:26 +04:00
}
2007-03-29 11:32:59 +04:00
len = p - name ;
2007-08-29 15:27:26 +04:00
if ( ! len )
goto err_free_param ;
if ( notnum ) {
param - > attrs [ i ] . alg . attr . rta_len =
sizeof ( param - > attrs [ i ] . alg ) ;
param - > attrs [ i ] . alg . attr . rta_type = CRYPTOA_ALG ;
memcpy ( param - > attrs [ i ] . alg . data . name , name , len ) ;
} else {
param - > attrs [ i ] . nu32 . attr . rta_len =
sizeof ( param - > attrs [ i ] . nu32 ) ;
param - > attrs [ i ] . nu32 . attr . rta_type = CRYPTOA_U32 ;
param - > attrs [ i ] . nu32 . data . num =
simple_strtol ( name , NULL , 0 ) ;
}
param - > tb [ i + 1 ] = & param - > attrs [ i ] . attr ;
i + + ;
2007-09-28 05:06:11 +04:00
if ( i > = CRYPTO_MAX_ATTRS )
2007-08-29 15:27:26 +04:00
goto err_free_param ;
if ( * p = = ' ) ' )
break ;
if ( * p ! = ' , ' )
goto err_free_param ;
2007-03-29 11:32:59 +04:00
}
2007-08-29 15:27:26 +04:00
if ( ! i )
2006-09-21 05:31:44 +04:00
goto err_free_param ;
2007-08-29 15:27:26 +04:00
param - > tb [ i + 1 ] = NULL ;
2007-01-01 10:37:02 +03:00
param - > type . attr . rta_len = sizeof ( param - > type ) ;
param - > type . attr . rta_type = CRYPTOA_TYPE ;
2008-08-03 17:15:23 +04:00
param - > type . data . type = larval - > alg . cra_flags & ~ CRYPTO_ALG_TESTED ;
param - > type . data . mask = larval - > mask & ~ CRYPTO_ALG_TESTED ;
2007-08-29 15:27:26 +04:00
param - > tb [ 0 ] = & param - > type . attr ;
2006-09-21 05:31:44 +04:00
2008-08-03 17:15:23 +04:00
param - > otype = larval - > alg . cra_flags ;
param - > omask = larval - > mask ;
2007-08-29 15:27:26 +04:00
memcpy ( param - > larval , larval - > alg . cra_name , CRYPTO_MAX_ALG_NAME ) ;
2006-09-21 05:31:44 +04:00
2008-08-03 17:15:23 +04:00
thread = kthread_run ( cryptomgr_probe , param , " cryptomgr_probe " ) ;
if ( IS_ERR ( thread ) )
goto err_free_param ;
return NOTIFY_STOP ;
err_free_param :
kfree ( param ) ;
err_put_module :
module_put ( THIS_MODULE ) ;
err :
return NOTIFY_OK ;
}
static int cryptomgr_test ( void * data )
{
struct crypto_test_param * param = data ;
u32 type = param - > type ;
int err = 0 ;
2009-02-18 16:41:29 +03:00
if ( type & CRYPTO_ALG_TESTED )
2008-08-03 17:15:23 +04:00
goto skiptest ;
2008-08-17 11:01:56 +04:00
err = alg_test ( param - > driver , param - > alg , type , CRYPTO_ALG_TESTED ) ;
2008-08-03 17:15:23 +04:00
skiptest :
crypto_alg_tested ( param - > driver , err ) ;
kfree ( param ) ;
module_put_and_exit ( 0 ) ;
}
static int cryptomgr_schedule_test ( struct crypto_alg * alg )
{
struct task_struct * thread ;
struct crypto_test_param * param ;
2009-02-18 16:41:29 +03:00
u32 type ;
2008-08-03 17:15:23 +04:00
if ( ! try_module_get ( THIS_MODULE ) )
goto err ;
param = kzalloc ( sizeof ( * param ) , GFP_KERNEL ) ;
if ( ! param )
goto err_put_module ;
memcpy ( param - > driver , alg - > cra_driver_name , sizeof ( param - > driver ) ) ;
memcpy ( param - > alg , alg - > cra_name , sizeof ( param - > alg ) ) ;
2009-02-18 16:41:29 +03:00
type = alg - > cra_flags ;
/* This piece of crap needs to disappear into per-type test hooks. */
if ( ( ! ( ( type ^ CRYPTO_ALG_TYPE_BLKCIPHER ) &
CRYPTO_ALG_TYPE_BLKCIPHER_MASK ) & & ! ( type & CRYPTO_ALG_GENIV ) & &
( ( alg - > cra_flags & CRYPTO_ALG_TYPE_MASK ) = =
CRYPTO_ALG_TYPE_BLKCIPHER ? alg - > cra_blkcipher . ivsize :
alg - > cra_ablkcipher . ivsize ) ) | |
( ! ( ( type ^ CRYPTO_ALG_TYPE_AEAD ) & CRYPTO_ALG_TYPE_MASK ) & &
alg - > cra_type = = & crypto_nivaead_type & & alg - > cra_aead . ivsize ) )
type | = CRYPTO_ALG_TESTED ;
param - > type = type ;
2008-08-03 17:15:23 +04:00
thread = kthread_run ( cryptomgr_test , param , " cryptomgr_test " ) ;
2007-05-09 07:04:39 +04:00
if ( IS_ERR ( thread ) )
2007-03-29 11:32:59 +04:00
goto err_free_param ;
2006-09-21 05:31:44 +04:00
return NOTIFY_STOP ;
err_free_param :
kfree ( param ) ;
2007-03-29 11:32:59 +04:00
err_put_module :
module_put ( THIS_MODULE ) ;
2006-09-21 05:31:44 +04:00
err :
return NOTIFY_OK ;
}
static int cryptomgr_notify ( struct notifier_block * this , unsigned long msg ,
void * data )
{
switch ( msg ) {
case CRYPTO_MSG_ALG_REQUEST :
return cryptomgr_schedule_probe ( data ) ;
2008-08-03 17:15:23 +04:00
case CRYPTO_MSG_ALG_REGISTER :
return cryptomgr_schedule_test ( data ) ;
2006-09-21 05:31:44 +04:00
}
return NOTIFY_DONE ;
}
static struct notifier_block cryptomgr_notifier = {
. notifier_call = cryptomgr_notify ,
} ;
static int __init cryptomgr_init ( void )
{
2009-05-06 10:15:47 +04:00
return crypto_register_notifier ( & cryptomgr_notifier ) ;
2006-09-21 05:31:44 +04:00
}
static void __exit cryptomgr_exit ( void )
{
int err = crypto_unregister_notifier ( & cryptomgr_notifier ) ;
BUG_ON ( err ) ;
}
2008-07-31 13:08:25 +04:00
subsys_initcall ( cryptomgr_init ) ;
2006-09-21 05:31:44 +04:00
module_exit ( cryptomgr_exit ) ;
MODULE_LICENSE ( " GPL " ) ;
MODULE_DESCRIPTION ( " Crypto Algorithm Manager " ) ;