#include <sys/types.h>
#include <sys/sunddi.h>
#include <sys/errno.h>
#include <sys/disp.h>
#include <sys/modctl.h>
#include <sys/modhash.h>
#include <sys/sysmacros.h>
#include <sys/crypto/common.h>
#include <sys/crypto/api.h>
#include <sys/crypto/impl.h>
kcf_mech_entry_t kcf_digest_mechs_tab[KCF_MAXDIGEST];
kcf_mech_entry_t kcf_cipher_mechs_tab[KCF_MAXCIPHER];
kcf_mech_entry_t kcf_mac_mechs_tab[KCF_MAXMAC];
kcf_mech_entry_t kcf_sign_mechs_tab[KCF_MAXSIGN];
kcf_mech_entry_t kcf_keyops_mechs_tab[KCF_MAXKEYOPS];
kcf_mech_entry_t kcf_misc_mechs_tab[KCF_MAXMISC];
kcf_mech_entry_tab_t kcf_mech_tabs_tab[KCF_LAST_OPSCLASS + 1] = {
{0, NULL},
{KCF_MAXDIGEST, kcf_digest_mechs_tab},
{KCF_MAXCIPHER, kcf_cipher_mechs_tab},
{KCF_MAXMAC, kcf_mac_mechs_tab},
{KCF_MAXSIGN, kcf_sign_mechs_tab},
{KCF_MAXKEYOPS, kcf_keyops_mechs_tab},
{KCF_MAXMISC, kcf_misc_mechs_tab}
};
kcf_lock_withpad_t *me_mutexes;
#define ME_MUTEXES_ENTER_ALL() \
for (int i = 0; i < max_ncpus; i++) \
mutex_enter(&me_mutexes[i].kl_lock);
#define ME_MUTEXES_EXIT_ALL() \
for (int i = 0; i < max_ncpus; i++) \
mutex_exit(&me_mutexes[i].kl_lock);
int kcf_md5_threshold = 512;
int kcf_sha1_threshold = 512;
int kcf_des_threshold = 512;
int kcf_des3_threshold = 512;
int kcf_aes_threshold = 512;
int kcf_bf_threshold = 512;
int kcf_rc4_threshold = 512;
kmutex_t kcf_mech_tabs_lock;
static uint32_t kcf_gen_swprov = 0;
int kcf_mech_hash_size = 256;
mod_hash_t *kcf_mech_hash;
static crypto_mech_type_t
kcf_mech_hash_find(char *mechname)
{
mod_hash_val_t hv;
crypto_mech_type_t mt;
mt = CRYPTO_MECH_INVALID;
if (mod_hash_find(kcf_mech_hash, (mod_hash_key_t)mechname, &hv) == 0) {
mt = *(crypto_mech_type_t *)hv;
ASSERT(mt != CRYPTO_MECH_INVALID);
}
return (mt);
}
void
kcf_init_mech_tabs()
{
int i, max;
kcf_ops_class_t class;
kcf_mech_entry_t *me_tab;
mutex_init(&kcf_mech_tabs_lock, NULL, MUTEX_DEFAULT, NULL);
(void) strncpy(kcf_digest_mechs_tab[0].me_name, SUN_CKM_MD5,
CRYPTO_MAX_MECH_NAME);
kcf_digest_mechs_tab[0].me_threshold = kcf_md5_threshold;
(void) strncpy(kcf_digest_mechs_tab[1].me_name, SUN_CKM_SHA1,
CRYPTO_MAX_MECH_NAME);
kcf_digest_mechs_tab[1].me_threshold = kcf_sha1_threshold;
CTASSERT(ARRAY_SIZE(kcf_digest_mechs_tab) >= 2);
(void) strncpy(kcf_cipher_mechs_tab[0].me_name, SUN_CKM_DES_CBC,
CRYPTO_MAX_MECH_NAME);
kcf_cipher_mechs_tab[0].me_threshold = kcf_des_threshold;
(void) strncpy(kcf_cipher_mechs_tab[1].me_name, SUN_CKM_DES3_CBC,
CRYPTO_MAX_MECH_NAME);
kcf_cipher_mechs_tab[1].me_threshold = kcf_des3_threshold;
(void) strncpy(kcf_cipher_mechs_tab[2].me_name, SUN_CKM_DES_ECB,
CRYPTO_MAX_MECH_NAME);
kcf_cipher_mechs_tab[2].me_threshold = kcf_des_threshold;
(void) strncpy(kcf_cipher_mechs_tab[3].me_name, SUN_CKM_DES3_ECB,
CRYPTO_MAX_MECH_NAME);
kcf_cipher_mechs_tab[3].me_threshold = kcf_des3_threshold;
(void) strncpy(kcf_cipher_mechs_tab[4].me_name, SUN_CKM_BLOWFISH_CBC,
CRYPTO_MAX_MECH_NAME);
kcf_cipher_mechs_tab[4].me_threshold = kcf_bf_threshold;
(void) strncpy(kcf_cipher_mechs_tab[5].me_name, SUN_CKM_BLOWFISH_ECB,
CRYPTO_MAX_MECH_NAME);
kcf_cipher_mechs_tab[5].me_threshold = kcf_bf_threshold;
(void) strncpy(kcf_cipher_mechs_tab[6].me_name, SUN_CKM_AES_CBC,
CRYPTO_MAX_MECH_NAME);
kcf_cipher_mechs_tab[6].me_threshold = kcf_aes_threshold;
(void) strncpy(kcf_cipher_mechs_tab[7].me_name, SUN_CKM_AES_ECB,
CRYPTO_MAX_MECH_NAME);
kcf_cipher_mechs_tab[7].me_threshold = kcf_aes_threshold;
(void) strncpy(kcf_cipher_mechs_tab[8].me_name, SUN_CKM_RC4,
CRYPTO_MAX_MECH_NAME);
kcf_cipher_mechs_tab[8].me_threshold = kcf_rc4_threshold;
(void) strncpy(kcf_cipher_mechs_tab[9].me_name, SUN_CKM_AES_CCM,
CRYPTO_MAX_MECH_NAME);
kcf_cipher_mechs_tab[9].me_copyin_param = kcf_copyin_aes_ccm_param;
(void) strncpy(kcf_cipher_mechs_tab[10].me_name, SUN_CKM_AES_GCM,
CRYPTO_MAX_MECH_NAME);
kcf_cipher_mechs_tab[10].me_copyin_param = kcf_copyin_aes_gcm_param;
CTASSERT(ARRAY_SIZE(kcf_cipher_mechs_tab) >= 11);
(void) strncpy(kcf_keyops_mechs_tab[0].me_name, SUN_CKM_ECDH1_DERIVE,
CRYPTO_MAX_MECH_NAME);
kcf_keyops_mechs_tab[0].me_copyin_param = kcf_copyin_ecdh1_param;
CTASSERT(ARRAY_SIZE(kcf_keyops_mechs_tab) >= 1);
(void) strncpy(kcf_mac_mechs_tab[0].me_name, SUN_CKM_MD5_HMAC,
CRYPTO_MAX_MECH_NAME);
kcf_mac_mechs_tab[0].me_threshold = kcf_md5_threshold;
(void) strncpy(kcf_mac_mechs_tab[1].me_name, SUN_CKM_MD5_HMAC_GENERAL,
CRYPTO_MAX_MECH_NAME);
kcf_mac_mechs_tab[1].me_threshold = kcf_md5_threshold;
(void) strncpy(kcf_mac_mechs_tab[2].me_name, SUN_CKM_SHA1_HMAC,
CRYPTO_MAX_MECH_NAME);
kcf_mac_mechs_tab[2].me_threshold = kcf_sha1_threshold;
(void) strncpy(kcf_mac_mechs_tab[3].me_name, SUN_CKM_SHA1_HMAC_GENERAL,
CRYPTO_MAX_MECH_NAME);
kcf_mac_mechs_tab[3].me_threshold = kcf_sha1_threshold;
(void) strncpy(kcf_mac_mechs_tab[4].me_name, SUN_CKM_AES_GMAC,
CRYPTO_MAX_MECH_NAME);
kcf_mac_mechs_tab[4].me_threshold = kcf_aes_threshold;
kcf_mac_mechs_tab[4].me_copyin_param = kcf_copyin_aes_gmac_param;
(void) strncpy(kcf_mac_mechs_tab[5].me_name, SUN_CKM_AES_CMAC,
CRYPTO_MAX_MECH_NAME);
kcf_mac_mechs_tab[5].me_threshold = kcf_aes_threshold;
CTASSERT(ARRAY_SIZE(kcf_mac_mechs_tab) >= 6);
(void) strncpy(kcf_misc_mechs_tab[0].me_name, SUN_RANDOM,
CRYPTO_MAX_MECH_NAME);
CTASSERT(ARRAY_SIZE(kcf_misc_mechs_tab) >= 1);
kcf_mech_hash = mod_hash_create_strhash("kcf mech2id hash",
kcf_mech_hash_size, mod_hash_null_valdtor);
for (class = KCF_FIRST_OPSCLASS; class <= KCF_LAST_OPSCLASS; class++) {
max = kcf_mech_tabs_tab[class].met_size;
me_tab = kcf_mech_tabs_tab[class].met_tab;
for (i = 0; i < max; i++) {
if (me_tab[i].me_name[0] != 0) {
me_tab[i].me_mechid = KCF_MECHID(class, i);
(void) mod_hash_insert(kcf_mech_hash,
(mod_hash_key_t)me_tab[i].me_name,
(mod_hash_val_t)&(me_tab[i].me_mechid));
}
}
}
me_mutexes = kmem_zalloc(max_ncpus * sizeof (kcf_lock_withpad_t),
KM_SLEEP);
for (i = 0; i < max_ncpus; i++) {
mutex_init(&me_mutexes[i].kl_lock, NULL, MUTEX_DEFAULT, NULL);
}
}
static int
kcf_create_mech_entry(kcf_ops_class_t class, char *mechname)
{
crypto_mech_type_t mt;
kcf_mech_entry_t *me_tab;
int i = 0, size;
if ((class < KCF_FIRST_OPSCLASS) || (class > KCF_LAST_OPSCLASS))
return (KCF_INVALID_MECH_CLASS);
if ((mechname == NULL) || (mechname[0] == 0))
return (KCF_INVALID_MECH_NAME);
mutex_enter(&kcf_mech_tabs_lock);
mt = kcf_mech_hash_find(mechname);
if (mt != CRYPTO_MECH_INVALID) {
mutex_exit(&kcf_mech_tabs_lock);
return (KCF_SUCCESS);
}
me_tab = kcf_mech_tabs_tab[class].met_tab;
size = kcf_mech_tabs_tab[class].met_size;
while (i < size) {
ME_MUTEXES_ENTER_ALL();
if (me_tab[i].me_name[0] == 0) {
(void) strncpy(me_tab[i].me_name, mechname,
CRYPTO_MAX_MECH_NAME);
me_tab[i].me_name[CRYPTO_MAX_MECH_NAME-1] = '\0';
me_tab[i].me_mechid = KCF_MECHID(class, i);
me_tab[i].me_threshold = 0;
me_tab[i].me_copyin_param = NULL;
ME_MUTEXES_EXIT_ALL();
(void) mod_hash_insert(kcf_mech_hash,
(mod_hash_key_t)me_tab[i].me_name,
(mod_hash_val_t)&(me_tab[i].me_mechid));
break;
}
ME_MUTEXES_EXIT_ALL();
i++;
}
mutex_exit(&kcf_mech_tabs_lock);
if (i == size) {
return (KCF_MECH_TAB_FULL);
}
return (KCF_SUCCESS);
}
int
kcf_add_mech_provider(short mech_indx,
kcf_provider_desc_t *prov_desc, kcf_prov_mech_desc_t **pmdpp)
{
int error;
kcf_mech_entry_t *mech_entry;
crypto_mech_info_t *mech_info;
crypto_mech_type_t kcf_mech_type, mt;
kcf_prov_mech_desc_t *prov_mech, *prov_mech2;
crypto_func_group_t simple_fg_mask, dual_fg_mask;
crypto_mech_info_t *dmi;
crypto_mech_info_list_t *mil, *mil2;
kcf_mech_entry_t *me;
int i;
ASSERT(prov_desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
mech_info = &prov_desc->pd_mechanisms[mech_indx];
if (is_mech_disabled(prov_desc, mech_info->cm_mech_name)) {
*pmdpp = NULL;
return (KCF_SUCCESS);
}
kcf_mech_type = kcf_mech_hash_find(mech_info->cm_mech_name);
if (kcf_mech_type == CRYPTO_MECH_INVALID) {
crypto_func_group_t fg = mech_info->cm_func_group_mask;
kcf_ops_class_t class;
if (fg & CRYPTO_FG_DIGEST || fg & CRYPTO_FG_DIGEST_ATOMIC)
class = KCF_DIGEST_CLASS;
else if (fg & CRYPTO_FG_ENCRYPT || fg & CRYPTO_FG_DECRYPT ||
fg & CRYPTO_FG_ENCRYPT_ATOMIC ||
fg & CRYPTO_FG_DECRYPT_ATOMIC)
class = KCF_CIPHER_CLASS;
else if (fg & CRYPTO_FG_MAC || fg & CRYPTO_FG_MAC_ATOMIC)
class = KCF_MAC_CLASS;
else if (fg & CRYPTO_FG_SIGN || fg & CRYPTO_FG_VERIFY ||
fg & CRYPTO_FG_SIGN_ATOMIC ||
fg & CRYPTO_FG_VERIFY_ATOMIC ||
fg & CRYPTO_FG_SIGN_RECOVER ||
fg & CRYPTO_FG_VERIFY_RECOVER)
class = KCF_SIGN_CLASS;
else if (fg & CRYPTO_FG_GENERATE ||
fg & CRYPTO_FG_GENERATE_KEY_PAIR ||
fg & CRYPTO_FG_WRAP || fg & CRYPTO_FG_UNWRAP ||
fg & CRYPTO_FG_DERIVE)
class = KCF_KEYOPS_CLASS;
else
class = KCF_MISC_CLASS;
if ((error = kcf_create_mech_entry(class,
mech_info->cm_mech_name)) != KCF_SUCCESS) {
return (error);
}
kcf_mech_type = kcf_mech_hash_find(mech_info->cm_mech_name);
ASSERT(kcf_mech_type != CRYPTO_MECH_INVALID);
}
error = kcf_get_mech_entry(kcf_mech_type, &mech_entry);
ASSERT(error == KCF_SUCCESS);
prov_mech = kmem_zalloc(sizeof (kcf_prov_mech_desc_t), KM_SLEEP);
bcopy(mech_info, &prov_mech->pm_mech_info, sizeof (crypto_mech_info_t));
prov_mech->pm_prov_desc = prov_desc;
prov_desc->pd_mech_indx[KCF_MECH2CLASS(kcf_mech_type)]
[KCF_MECH2INDEX(kcf_mech_type)] = mech_indx;
KCF_PROV_REFHOLD(prov_desc);
dual_fg_mask = mech_info->cm_func_group_mask & CRYPTO_FG_DUAL_MASK;
if (dual_fg_mask == ((crypto_func_group_t)0))
goto add_entry;
simple_fg_mask = mech_info->cm_func_group_mask &
CRYPTO_FG_SIMPLEOP_MASK | CRYPTO_FG_RANDOM;
for (i = 0; i < prov_desc->pd_mech_list_count; i++) {
dmi = &prov_desc->pd_mechanisms[i];
if (dmi->cm_mech_number == mech_info->cm_mech_number)
continue;
if (is_mech_disabled(prov_desc, dmi->cm_mech_name))
continue;
if (!(dmi->cm_func_group_mask & dual_fg_mask) ||
(dmi->cm_func_group_mask & simple_fg_mask))
continue;
mt = kcf_mech_hash_find(dmi->cm_mech_name);
if (mt == CRYPTO_MECH_INVALID)
continue;
if (kcf_get_mech_entry(mt, &me) != KCF_SUCCESS)
continue;
mil = kmem_zalloc(sizeof (*mil), KM_SLEEP);
mil2 = kmem_zalloc(sizeof (*mil2), KM_SLEEP);
ME_MUTEXES_ENTER_ALL();
if (me->me_hw_prov_chain == NULL && me->me_sw_prov == NULL) {
ME_MUTEXES_EXIT_ALL();
kmem_free(mil, sizeof (*mil));
kmem_free(mil2, sizeof (*mil2));
continue;
}
mil->ml_mech_info = *dmi;
mil->ml_kcf_mechid = mt;
mil->ml_next = prov_mech->pm_mi_list;
prov_mech->pm_mi_list = mil;
if (prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER)
prov_mech2 = me->me_hw_prov_chain;
else
prov_mech2 = me->me_sw_prov;
if (prov_mech2 == NULL) {
kmem_free(mil2, sizeof (*mil2));
ME_MUTEXES_EXIT_ALL();
continue;
}
while (prov_mech2 != NULL) {
if (prov_mech2->pm_prov_desc == prov_desc) {
mil2->ml_mech_info = *mech_info;
mil2->ml_kcf_mechid = kcf_mech_type;
mil2->ml_next = prov_mech2->pm_mi_list;
prov_mech2->pm_mi_list = mil2;
break;
}
prov_mech2 = prov_mech2->pm_next;
}
if (prov_mech2 == NULL)
kmem_free(mil2, sizeof (*mil2));
ME_MUTEXES_EXIT_ALL();
}
add_entry:
switch (prov_desc->pd_prov_type) {
case CRYPTO_HW_PROVIDER:
ME_MUTEXES_ENTER_ALL();
prov_mech->pm_me = mech_entry;
prov_mech->pm_next = mech_entry->me_hw_prov_chain;
mech_entry->me_hw_prov_chain = prov_mech;
mech_entry->me_num_hwprov++;
ME_MUTEXES_EXIT_ALL();
break;
case CRYPTO_SW_PROVIDER:
ME_MUTEXES_ENTER_ALL();
if (mech_entry->me_sw_prov != NULL) {
cmn_err(CE_WARN, "The cryptographic software provider "
"\"%s\" will not be used for %s. The provider "
"\"%s\" will be used for this mechanism "
"instead.", prov_desc->pd_description,
mech_info->cm_mech_name,
mech_entry->me_sw_prov->pm_prov_desc->
pd_description);
KCF_PROV_REFRELE(prov_desc);
kmem_free(prov_mech, sizeof (kcf_prov_mech_desc_t));
prov_mech = NULL;
} else {
mech_entry->me_sw_prov = prov_mech;
mech_entry->me_gen_swprov = kcf_gen_swprov++;
}
ME_MUTEXES_EXIT_ALL();
break;
}
*pmdpp = prov_mech;
return (KCF_SUCCESS);
}
void
kcf_remove_mech_provider(char *mech_name, kcf_provider_desc_t *prov_desc)
{
crypto_mech_type_t mech_type;
kcf_prov_mech_desc_t *prov_mech, *prov_chain;
kcf_prov_mech_desc_t **prev_entry_next;
kcf_mech_entry_t *mech_entry;
crypto_mech_info_list_t *mil, *mil2, *next, **prev_next;
ASSERT(prov_desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
if ((mech_type = kcf_mech_hash_find(mech_name)) ==
CRYPTO_MECH_INVALID) {
return;
}
if (kcf_get_mech_entry(mech_type, &mech_entry) != KCF_SUCCESS) {
return;
}
ME_MUTEXES_ENTER_ALL();
switch (prov_desc->pd_prov_type) {
case CRYPTO_HW_PROVIDER:
prev_entry_next = &mech_entry->me_hw_prov_chain;
prov_mech = mech_entry->me_hw_prov_chain;
while (prov_mech != NULL &&
prov_mech->pm_prov_desc != prov_desc) {
prev_entry_next = &prov_mech->pm_next;
prov_mech = prov_mech->pm_next;
}
if (prov_mech == NULL) {
ME_MUTEXES_EXIT_ALL();
return;
}
*prev_entry_next = prov_mech->pm_next;
ASSERT(mech_entry->me_num_hwprov > 0);
mech_entry->me_num_hwprov--;
break;
case CRYPTO_SW_PROVIDER:
if (mech_entry->me_sw_prov == NULL ||
mech_entry->me_sw_prov->pm_prov_desc != prov_desc) {
ME_MUTEXES_EXIT_ALL();
return;
}
prov_mech = mech_entry->me_sw_prov;
mech_entry->me_sw_prov = NULL;
break;
}
ME_MUTEXES_EXIT_ALL();
mil = prov_mech->pm_mi_list;
while (mil != NULL) {
next = mil->ml_next;
if (kcf_get_mech_entry(mil->ml_kcf_mechid,
&mech_entry) != KCF_SUCCESS) {
mil = next;
continue;
}
ME_MUTEXES_ENTER_ALL();
if (prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER)
prov_chain = mech_entry->me_hw_prov_chain;
else
prov_chain = mech_entry->me_sw_prov;
while (prov_chain != NULL) {
if (prov_chain->pm_prov_desc == prov_desc) {
prev_next = &prov_chain->pm_mi_list;
mil2 = prov_chain->pm_mi_list;
while (mil2 != NULL &&
mil2->ml_kcf_mechid != mech_type) {
prev_next = &mil2->ml_next;
mil2 = mil2->ml_next;
}
if (mil2 != NULL) {
*prev_next = mil2->ml_next;
kmem_free(mil2, sizeof (*mil2));
}
break;
}
prov_chain = prov_chain->pm_next;
}
ME_MUTEXES_EXIT_ALL();
kmem_free(mil, sizeof (crypto_mech_info_list_t));
mil = next;
}
KCF_PROV_REFRELE(prov_mech->pm_prov_desc);
kmem_free(prov_mech, sizeof (kcf_prov_mech_desc_t));
}
int
kcf_get_mech_entry(crypto_mech_type_t mech_type, kcf_mech_entry_t **mep)
{
kcf_ops_class_t class;
int index;
kcf_mech_entry_tab_t *me_tab;
ASSERT(mep != NULL);
class = KCF_MECH2CLASS(mech_type);
if ((class < KCF_FIRST_OPSCLASS) || (class > KCF_LAST_OPSCLASS)) {
return (KCF_INVALID_MECH_NUMBER);
}
me_tab = &kcf_mech_tabs_tab[class];
index = KCF_MECH2INDEX(mech_type);
if ((index < 0) || (index >= me_tab->met_size)) {
return (KCF_INVALID_MECH_NUMBER);
}
*mep = &((me_tab->met_tab)[index]);
return (KCF_SUCCESS);
}
static boolean_t
auto_unload_flag_set(kcf_prov_mech_desc_t *pm)
{
kcf_provider_desc_t *pd;
struct modctl *mp;
boolean_t ret = B_FALSE;
if (pm != NULL) {
pd = pm->pm_prov_desc;
KCF_PROV_REFHOLD(pd);
if (KCF_IS_PROV_USABLE(pd)) {
mp = pd->pd_mctlp;
if (mp->mod_loadflags & MOD_NOAUTOUNLOAD) {
ret = B_TRUE;
}
}
KCF_PROV_REFRELE(pd);
}
return (ret);
}
crypto_mech_type_t
crypto_mech2id_common(char *mechname, boolean_t load_module)
{
crypto_mech_type_t mt;
kcf_mech_entry_t *me;
int i;
kcf_ops_class_t class;
boolean_t second_time = B_FALSE;
boolean_t try_to_load_software_provider = B_FALSE;
kcf_lock_withpad_t *mp;
try_again:
mt = kcf_mech_hash_find(mechname);
if (!load_module || second_time == B_TRUE || servicing_interrupt())
return (mt);
if (mt != CRYPTO_MECH_INVALID) {
class = KCF_MECH2CLASS(mt);
i = KCF_MECH2INDEX(mt);
me = &(kcf_mech_tabs_tab[class].met_tab[i]);
mp = &me_mutexes[CPU_SEQID];
mutex_enter(&mp->kl_lock);
if (load_module && !auto_unload_flag_set(me->me_sw_prov)) {
try_to_load_software_provider = B_TRUE;
}
mutex_exit(&mp->kl_lock);
}
if (mt == CRYPTO_MECH_INVALID || try_to_load_software_provider) {
struct modctl *mcp;
boolean_t load_again = B_FALSE;
char *module_name;
int module_name_size;
if (get_sw_provider_for_mech(mechname, &module_name)
!= CRYPTO_SUCCESS) {
return (mt);
}
module_name_size = strlen(module_name) + 1;
if (modload("crypto", module_name) == -1 ||
(mcp = mod_hold_by_name(module_name)) == NULL) {
kmem_free(module_name, module_name_size);
return (mt);
}
mcp->mod_loadflags |= MOD_NOAUTOUNLOAD;
if (!mcp->mod_installed)
load_again = B_TRUE;
mod_release_mod(mcp);
if (load_again)
(void) modload("crypto", module_name);
kmem_free(module_name, module_name_size);
if (mt != CRYPTO_MECH_INVALID)
return (mt);
second_time = B_TRUE;
goto try_again;
}
return (mt);
}