17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
56f3f1c68Skrishna  * Common Development and Distribution License (the "License").
66f3f1c68Skrishna  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22983a1033SMark Powers  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #include <sys/types.h>
277c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
287c478bd9Sstevel@tonic-gate #include <sys/errno.h>
297c478bd9Sstevel@tonic-gate #include <sys/disp.h>
307c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
316f3f1c68Skrishna #include <sys/modhash.h>
327c478bd9Sstevel@tonic-gate #include <sys/crypto/common.h>
337c478bd9Sstevel@tonic-gate #include <sys/crypto/api.h>
347c478bd9Sstevel@tonic-gate #include <sys/crypto/impl.h>
357c478bd9Sstevel@tonic-gate 
367c478bd9Sstevel@tonic-gate /* Cryptographic mechanisms tables and their access functions */
377c478bd9Sstevel@tonic-gate 
387c478bd9Sstevel@tonic-gate /*
397c478bd9Sstevel@tonic-gate  * Internal numbers assigned to mechanisms are coded as follows:
407c478bd9Sstevel@tonic-gate  *
417c478bd9Sstevel@tonic-gate  * +----------------+----------------+
427c478bd9Sstevel@tonic-gate  * | mech. class    | mech. index    |
437c478bd9Sstevel@tonic-gate  * <--- 32-bits --->+<--- 32-bits --->
447c478bd9Sstevel@tonic-gate  *
457c478bd9Sstevel@tonic-gate  * the mech_class identifies the table the mechanism belongs to.
467c478bd9Sstevel@tonic-gate  * mech_index  is the index for that mechanism in the table.
477c478bd9Sstevel@tonic-gate  * A mechanism belongs to exactly 1 table.
487c478bd9Sstevel@tonic-gate  * The tables are:
497c478bd9Sstevel@tonic-gate  * . digest_mechs_tab[] for the msg digest mechs.
507c478bd9Sstevel@tonic-gate  * . cipher_mechs_tab[] for encrypt/decrypt and wrap/unwrap mechs.
517c478bd9Sstevel@tonic-gate  * . mac_mechs_tab[] for MAC mechs.
527c478bd9Sstevel@tonic-gate  * . sign_mechs_tab[] for sign & verify mechs.
537c478bd9Sstevel@tonic-gate  * . keyops_mechs_tab[] for key/key pair generation, and key derivation.
547c478bd9Sstevel@tonic-gate  * . misc_mechs_tab[] for mechs that don't belong to any of the above.
557c478bd9Sstevel@tonic-gate  *
567c478bd9Sstevel@tonic-gate  * There are no holes in the tables.
577c478bd9Sstevel@tonic-gate  */
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate /*
607c478bd9Sstevel@tonic-gate  * Locking conventions:
617c478bd9Sstevel@tonic-gate  * --------------------
627c478bd9Sstevel@tonic-gate  * A global mutex, kcf_mech_tabs_lock, serializes writes to the
637c478bd9Sstevel@tonic-gate  * mechanism table via kcf_create_mech_entry().
647c478bd9Sstevel@tonic-gate  *
657c478bd9Sstevel@tonic-gate  * A mutex is associated with every entry of the tables.
667c478bd9Sstevel@tonic-gate  * The mutex is acquired whenever the entry is accessed for
677c478bd9Sstevel@tonic-gate  * 1) retrieving the mech_id (comparing the mech name)
687c478bd9Sstevel@tonic-gate  * 2) finding a provider for an xxx_init() or atomic operation.
697c478bd9Sstevel@tonic-gate  * 3) altering the mechs entry to add or remove a provider.
707c478bd9Sstevel@tonic-gate  *
717c478bd9Sstevel@tonic-gate  * In 2), after a provider is chosen, its prov_desc is held and the
727c478bd9Sstevel@tonic-gate  * entry's mutex must be dropped. The provider's working function (SPI) is
737c478bd9Sstevel@tonic-gate  * called outside the mech_entry's mutex.
747c478bd9Sstevel@tonic-gate  *
757c478bd9Sstevel@tonic-gate  * The number of providers for a particular mechanism is not expected to be
767c478bd9Sstevel@tonic-gate  * long enough to justify the cost of using rwlocks, so the per-mechanism
777c478bd9Sstevel@tonic-gate  * entry mutex won't be very *hot*.
787c478bd9Sstevel@tonic-gate  *
797c478bd9Sstevel@tonic-gate  * When both kcf_mech_tabs_lock and a mech_entry mutex need to be held,
807c478bd9Sstevel@tonic-gate  * kcf_mech_tabs_lock must always be acquired first.
817c478bd9Sstevel@tonic-gate  *
827c478bd9Sstevel@tonic-gate  */
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate 		/* Mechanisms tables */
857c478bd9Sstevel@tonic-gate 
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate /* RFE 4687834 Will deal with the extensibility of these tables later */
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate kcf_mech_entry_t kcf_digest_mechs_tab[KCF_MAXDIGEST];
907c478bd9Sstevel@tonic-gate kcf_mech_entry_t kcf_cipher_mechs_tab[KCF_MAXCIPHER];
917c478bd9Sstevel@tonic-gate kcf_mech_entry_t kcf_mac_mechs_tab[KCF_MAXMAC];
927c478bd9Sstevel@tonic-gate kcf_mech_entry_t kcf_sign_mechs_tab[KCF_MAXSIGN];
937c478bd9Sstevel@tonic-gate kcf_mech_entry_t kcf_keyops_mechs_tab[KCF_MAXKEYOPS];
947c478bd9Sstevel@tonic-gate kcf_mech_entry_t kcf_misc_mechs_tab[KCF_MAXMISC];
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate kcf_mech_entry_tab_t kcf_mech_tabs_tab[KCF_LAST_OPSCLASS + 1] = {
977c478bd9Sstevel@tonic-gate 	{0, NULL},				/* No class zero */
987c478bd9Sstevel@tonic-gate 	{KCF_MAXDIGEST, kcf_digest_mechs_tab},
997c478bd9Sstevel@tonic-gate 	{KCF_MAXCIPHER, kcf_cipher_mechs_tab},
1007c478bd9Sstevel@tonic-gate 	{KCF_MAXMAC, kcf_mac_mechs_tab},
1017c478bd9Sstevel@tonic-gate 	{KCF_MAXSIGN, kcf_sign_mechs_tab},
1027c478bd9Sstevel@tonic-gate 	{KCF_MAXKEYOPS, kcf_keyops_mechs_tab},
1037c478bd9Sstevel@tonic-gate 	{KCF_MAXMISC, kcf_misc_mechs_tab}
1047c478bd9Sstevel@tonic-gate };
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate /*
107ef56a3c5SKrishna Yenduri  * Protects fields in kcf_mech_entry. This is an array
108ef56a3c5SKrishna Yenduri  * of locks indexed by the cpuid. A reader needs to hold
109ef56a3c5SKrishna Yenduri  * a single lock while a writer needs to hold all locks.
110ef56a3c5SKrishna Yenduri  * krwlock_t is not an option here because the hold time
111ef56a3c5SKrishna Yenduri  * is very small for these locks.
112ef56a3c5SKrishna Yenduri  */
113ef56a3c5SKrishna Yenduri kcf_lock_withpad_t *me_mutexes;
114ef56a3c5SKrishna Yenduri 
115ef56a3c5SKrishna Yenduri #define	ME_MUTEXES_ENTER_ALL()	\
116ef56a3c5SKrishna Yenduri 	for (int i = 0; i < max_ncpus; i++)	\
117ef56a3c5SKrishna Yenduri 		mutex_enter(&me_mutexes[i].kl_lock);
118ef56a3c5SKrishna Yenduri 
119ef56a3c5SKrishna Yenduri #define	ME_MUTEXES_EXIT_ALL()	\
120ef56a3c5SKrishna Yenduri 	for (int i = 0; i < max_ncpus; i++)	\
121ef56a3c5SKrishna Yenduri 		mutex_exit(&me_mutexes[i].kl_lock);
122ef56a3c5SKrishna Yenduri 
123ef56a3c5SKrishna Yenduri /*
124ef56a3c5SKrishna Yenduri  * Per-algorithm internal thresholds for the minimum input size of before
1257c478bd9Sstevel@tonic-gate  * offloading to hardware provider.
1267c478bd9Sstevel@tonic-gate  * Dispatching a crypto operation  to a hardware provider entails paying the
1277c478bd9Sstevel@tonic-gate  * cost of an additional context switch.  Measurments with Sun Accelerator 4000
1287c478bd9Sstevel@tonic-gate  * shows that 512-byte jobs or smaller are better handled in software.
1297c478bd9Sstevel@tonic-gate  * There is room for refinement here.
1307c478bd9Sstevel@tonic-gate  *
1317c478bd9Sstevel@tonic-gate  */
1327c478bd9Sstevel@tonic-gate int kcf_md5_threshold = 512;
1337c478bd9Sstevel@tonic-gate int kcf_sha1_threshold = 512;
1347c478bd9Sstevel@tonic-gate int kcf_des_threshold = 512;
1357c478bd9Sstevel@tonic-gate int kcf_des3_threshold = 512;
1367c478bd9Sstevel@tonic-gate int kcf_aes_threshold = 512;
1377c478bd9Sstevel@tonic-gate int kcf_bf_threshold = 512;
1386f3f1c68Skrishna int kcf_rc4_threshold = 512;
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate kmutex_t kcf_mech_tabs_lock;
1417c478bd9Sstevel@tonic-gate static uint32_t kcf_gen_swprov = 0;
1427c478bd9Sstevel@tonic-gate 
1436f3f1c68Skrishna int kcf_mech_hash_size = 256;
1446f3f1c68Skrishna mod_hash_t *kcf_mech_hash;	/* mech name to id hash */
1456f3f1c68Skrishna 
1466f3f1c68Skrishna static crypto_mech_type_t
kcf_mech_hash_find(char * mechname)1476f3f1c68Skrishna kcf_mech_hash_find(char *mechname)
1486f3f1c68Skrishna {
1496f3f1c68Skrishna 	mod_hash_val_t hv;
1506f3f1c68Skrishna 	crypto_mech_type_t mt;
1516f3f1c68Skrishna 
1526f3f1c68Skrishna 	mt = CRYPTO_MECH_INVALID;
1536f3f1c68Skrishna 	if (mod_hash_find(kcf_mech_hash, (mod_hash_key_t)mechname, &hv) == 0) {
1546f3f1c68Skrishna 		mt = *(crypto_mech_type_t *)hv;
1556f3f1c68Skrishna 		ASSERT(mt != CRYPTO_MECH_INVALID);
1566f3f1c68Skrishna 	}
1576f3f1c68Skrishna 
1586f3f1c68Skrishna 	return (mt);
1596f3f1c68Skrishna }
1606f3f1c68Skrishna 
1617c478bd9Sstevel@tonic-gate /*
1627c478bd9Sstevel@tonic-gate  * kcf_init_mech_tabs()
1637c478bd9Sstevel@tonic-gate  *
1647c478bd9Sstevel@tonic-gate  * Called by the misc/kcf's _init() routine to initialize the tables
1657c478bd9Sstevel@tonic-gate  * of mech_entry's.
1667c478bd9Sstevel@tonic-gate  */
1677c478bd9Sstevel@tonic-gate void
kcf_init_mech_tabs()1687c478bd9Sstevel@tonic-gate kcf_init_mech_tabs()
1697c478bd9Sstevel@tonic-gate {
1707c478bd9Sstevel@tonic-gate 	int i, max;
1717c478bd9Sstevel@tonic-gate 	kcf_ops_class_t class;
1727c478bd9Sstevel@tonic-gate 	kcf_mech_entry_t *me_tab;
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 	/* Initializes the mutex locks. */
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	mutex_init(&kcf_mech_tabs_lock, NULL, MUTEX_DEFAULT, NULL);
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate 	/* Then the pre-defined mechanism entries */
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 	/* Two digests */
1817c478bd9Sstevel@tonic-gate 	(void) strncpy(kcf_digest_mechs_tab[0].me_name, SUN_CKM_MD5,
1827c478bd9Sstevel@tonic-gate 	    CRYPTO_MAX_MECH_NAME);
1837c478bd9Sstevel@tonic-gate 	kcf_digest_mechs_tab[0].me_threshold = kcf_md5_threshold;
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate 	(void) strncpy(kcf_digest_mechs_tab[1].me_name, SUN_CKM_SHA1,
1867c478bd9Sstevel@tonic-gate 	    CRYPTO_MAX_MECH_NAME);
1877c478bd9Sstevel@tonic-gate 	kcf_digest_mechs_tab[1].me_threshold = kcf_sha1_threshold;
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate 	/* The symmetric ciphers in various modes */
1907c478bd9Sstevel@tonic-gate 	(void) strncpy(kcf_cipher_mechs_tab[0].me_name, SUN_CKM_DES_CBC,
1917c478bd9Sstevel@tonic-gate 	    CRYPTO_MAX_MECH_NAME);
1927c478bd9Sstevel@tonic-gate 	kcf_cipher_mechs_tab[0].me_threshold = kcf_des_threshold;
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate 	(void) strncpy(kcf_cipher_mechs_tab[1].me_name, SUN_CKM_DES3_CBC,
1957c478bd9Sstevel@tonic-gate 	    CRYPTO_MAX_MECH_NAME);
1967c478bd9Sstevel@tonic-gate 	kcf_cipher_mechs_tab[1].me_threshold = kcf_des3_threshold;
1977c478bd9Sstevel@tonic-gate 
1987c478bd9Sstevel@tonic-gate 	(void) strncpy(kcf_cipher_mechs_tab[2].me_name, SUN_CKM_DES_ECB,
1997c478bd9Sstevel@tonic-gate 	    CRYPTO_MAX_MECH_NAME);
2007c478bd9Sstevel@tonic-gate 	kcf_cipher_mechs_tab[2].me_threshold = kcf_des_threshold;
2017c478bd9Sstevel@tonic-gate 
2027c478bd9Sstevel@tonic-gate 	(void) strncpy(kcf_cipher_mechs_tab[3].me_name, SUN_CKM_DES3_ECB,
2037c478bd9Sstevel@tonic-gate 	    CRYPTO_MAX_MECH_NAME);
2047c478bd9Sstevel@tonic-gate 	kcf_cipher_mechs_tab[3].me_threshold = kcf_des3_threshold;
2057c478bd9Sstevel@tonic-gate 
206f66d273dSizick 	(void) strncpy(kcf_cipher_mechs_tab[4].me_name, SUN_CKM_BLOWFISH_CBC,
2077c478bd9Sstevel@tonic-gate 	    CRYPTO_MAX_MECH_NAME);
2087c478bd9Sstevel@tonic-gate 	kcf_cipher_mechs_tab[4].me_threshold = kcf_bf_threshold;
2097c478bd9Sstevel@tonic-gate 
210f66d273dSizick 	(void) strncpy(kcf_cipher_mechs_tab[5].me_name, SUN_CKM_BLOWFISH_ECB,
2117c478bd9Sstevel@tonic-gate 	    CRYPTO_MAX_MECH_NAME);
2127c478bd9Sstevel@tonic-gate 	kcf_cipher_mechs_tab[5].me_threshold = kcf_bf_threshold;
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate 	(void) strncpy(kcf_cipher_mechs_tab[6].me_name, SUN_CKM_AES_CBC,
2157c478bd9Sstevel@tonic-gate 	    CRYPTO_MAX_MECH_NAME);
2167c478bd9Sstevel@tonic-gate 	kcf_cipher_mechs_tab[6].me_threshold = kcf_aes_threshold;
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 	(void) strncpy(kcf_cipher_mechs_tab[7].me_name, SUN_CKM_AES_ECB,
2197c478bd9Sstevel@tonic-gate 	    CRYPTO_MAX_MECH_NAME);
2207c478bd9Sstevel@tonic-gate 	kcf_cipher_mechs_tab[7].me_threshold = kcf_aes_threshold;
2217c478bd9Sstevel@tonic-gate 
2226f3f1c68Skrishna 	(void) strncpy(kcf_cipher_mechs_tab[8].me_name, SUN_CKM_RC4,
2236f3f1c68Skrishna 	    CRYPTO_MAX_MECH_NAME);
2246f3f1c68Skrishna 	kcf_cipher_mechs_tab[8].me_threshold = kcf_rc4_threshold;
2256f3f1c68Skrishna 
2267c478bd9Sstevel@tonic-gate 
227*cd964fceSMatt Barden 	/* 6 HMACs */
2287c478bd9Sstevel@tonic-gate 	(void) strncpy(kcf_mac_mechs_tab[0].me_name, SUN_CKM_MD5_HMAC,
2297c478bd9Sstevel@tonic-gate 	    CRYPTO_MAX_MECH_NAME);
2307c478bd9Sstevel@tonic-gate 	kcf_mac_mechs_tab[0].me_threshold = kcf_md5_threshold;
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 	(void) strncpy(kcf_mac_mechs_tab[1].me_name, SUN_CKM_MD5_HMAC_GENERAL,
2337c478bd9Sstevel@tonic-gate 	    CRYPTO_MAX_MECH_NAME);
2347c478bd9Sstevel@tonic-gate 	kcf_mac_mechs_tab[1].me_threshold = kcf_md5_threshold;
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate 	(void) strncpy(kcf_mac_mechs_tab[2].me_name, SUN_CKM_SHA1_HMAC,
2377c478bd9Sstevel@tonic-gate 	    CRYPTO_MAX_MECH_NAME);
2387c478bd9Sstevel@tonic-gate 	kcf_mac_mechs_tab[2].me_threshold = kcf_sha1_threshold;
2397c478bd9Sstevel@tonic-gate 
2407c478bd9Sstevel@tonic-gate 	(void) strncpy(kcf_mac_mechs_tab[3].me_name, SUN_CKM_SHA1_HMAC_GENERAL,
2417c478bd9Sstevel@tonic-gate 	    CRYPTO_MAX_MECH_NAME);
2427c478bd9Sstevel@tonic-gate 	kcf_mac_mechs_tab[3].me_threshold = kcf_sha1_threshold;
2437c478bd9Sstevel@tonic-gate 
244983a1033SMark Powers 	(void) strncpy(kcf_mac_mechs_tab[4].me_name, SUN_CKM_AES_GMAC,
245983a1033SMark Powers 	    CRYPTO_MAX_MECH_NAME);
246983a1033SMark Powers 	kcf_mac_mechs_tab[4].me_threshold = kcf_sha1_threshold;
2477c478bd9Sstevel@tonic-gate 
248*cd964fceSMatt Barden 	(void) strncpy(kcf_mac_mechs_tab[5].me_name, SUN_CKM_AES_CMAC,
249*cd964fceSMatt Barden 	    CRYPTO_MAX_MECH_NAME);
250*cd964fceSMatt Barden 	kcf_mac_mechs_tab[5].me_threshold = kcf_sha1_threshold;
251*cd964fceSMatt Barden 
2527c478bd9Sstevel@tonic-gate 	/* 1 random number generation pseudo mechanism */
2537c478bd9Sstevel@tonic-gate 	(void) strncpy(kcf_misc_mechs_tab[0].me_name, SUN_RANDOM,
2547c478bd9Sstevel@tonic-gate 	    CRYPTO_MAX_MECH_NAME);
2557c478bd9Sstevel@tonic-gate 
2566f3f1c68Skrishna 	kcf_mech_hash = mod_hash_create_strhash("kcf mech2id hash",
2576f3f1c68Skrishna 	    kcf_mech_hash_size, mod_hash_null_valdtor);
2586f3f1c68Skrishna 
2596f3f1c68Skrishna 	for (class = KCF_FIRST_OPSCLASS; class <= KCF_LAST_OPSCLASS; class++) {
2606f3f1c68Skrishna 		max = kcf_mech_tabs_tab[class].met_size;
2616f3f1c68Skrishna 		me_tab = kcf_mech_tabs_tab[class].met_tab;
2626f3f1c68Skrishna 		for (i = 0; i < max; i++) {
2636f3f1c68Skrishna 			if (me_tab[i].me_name[0] != 0) {
2646f3f1c68Skrishna 				me_tab[i].me_mechid = KCF_MECHID(class, i);
2656f3f1c68Skrishna 				(void) mod_hash_insert(kcf_mech_hash,
2666f3f1c68Skrishna 				    (mod_hash_key_t)me_tab[i].me_name,
2676f3f1c68Skrishna 				    (mod_hash_val_t)&(me_tab[i].me_mechid));
2686f3f1c68Skrishna 			}
2696f3f1c68Skrishna 		}
2706f3f1c68Skrishna 	}
271ef56a3c5SKrishna Yenduri 
272ef56a3c5SKrishna Yenduri 	me_mutexes = kmem_zalloc(max_ncpus * sizeof (kcf_lock_withpad_t),
273ef56a3c5SKrishna Yenduri 	    KM_SLEEP);
274ef56a3c5SKrishna Yenduri 	for (i = 0; i < max_ncpus; i++) {
275ef56a3c5SKrishna Yenduri 		mutex_init(&me_mutexes[i].kl_lock, NULL, MUTEX_DEFAULT, NULL);
276ef56a3c5SKrishna Yenduri 	}
2777c478bd9Sstevel@tonic-gate }
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate /*
2807c478bd9Sstevel@tonic-gate  * kcf_create_mech_entry()
2817c478bd9Sstevel@tonic-gate  *
2827c478bd9Sstevel@tonic-gate  * Arguments:
2837c478bd9Sstevel@tonic-gate  *	. The class of mechanism.
2847c478bd9Sstevel@tonic-gate  *	. the name of the new mechanism.
2857c478bd9Sstevel@tonic-gate  *
2867c478bd9Sstevel@tonic-gate  * Description:
2877c478bd9Sstevel@tonic-gate  *	Creates a new mech_entry for a mechanism not yet known to the
2887c478bd9Sstevel@tonic-gate  *	framework.
2897c478bd9Sstevel@tonic-gate  *	This routine is called by kcf_add_mech_provider, which is
2907c478bd9Sstevel@tonic-gate  *	in turn invoked for each mechanism supported by a provider.
2917c478bd9Sstevel@tonic-gate  *	The'class' argument depends on the crypto_func_group_t bitmask
2927c478bd9Sstevel@tonic-gate  *	in the registering provider's mech_info struct for this mechanism.
2937c478bd9Sstevel@tonic-gate  *	When there is ambiguity in the mapping between the crypto_func_group_t
2947c478bd9Sstevel@tonic-gate  *	and a class (dual ops, ...) the KCF_MISC_CLASS should be used.
2957c478bd9Sstevel@tonic-gate  *
2967c478bd9Sstevel@tonic-gate  * Context:
2977c478bd9Sstevel@tonic-gate  *	User context only.
2987c478bd9Sstevel@tonic-gate  *
2997c478bd9Sstevel@tonic-gate  * Returns:
3007c478bd9Sstevel@tonic-gate  *	KCF_INVALID_MECH_CLASS or KCF_INVALID_MECH_NAME if the class or
3017c478bd9Sstevel@tonic-gate  *	the mechname is bogus.
3027c478bd9Sstevel@tonic-gate  *	KCF_MECH_TAB_FULL when there is no room left in the mech. tabs.
3037c478bd9Sstevel@tonic-gate  *	KCF_SUCCESS otherwise.
3047c478bd9Sstevel@tonic-gate  */
3057c478bd9Sstevel@tonic-gate static int
kcf_create_mech_entry(kcf_ops_class_t class,char * mechname)3067c478bd9Sstevel@tonic-gate kcf_create_mech_entry(kcf_ops_class_t class, char *mechname)
3077c478bd9Sstevel@tonic-gate {
3087c478bd9Sstevel@tonic-gate 	crypto_mech_type_t mt;
3097c478bd9Sstevel@tonic-gate 	kcf_mech_entry_t *me_tab;
3107c478bd9Sstevel@tonic-gate 	int i = 0, size;
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 	if ((class < KCF_FIRST_OPSCLASS) || (class > KCF_LAST_OPSCLASS))
3137c478bd9Sstevel@tonic-gate 		return (KCF_INVALID_MECH_CLASS);
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	if ((mechname == NULL) || (mechname[0] == 0))
3167c478bd9Sstevel@tonic-gate 		return (KCF_INVALID_MECH_NAME);
3177c478bd9Sstevel@tonic-gate 	/*
3187c478bd9Sstevel@tonic-gate 	 * First check if the mechanism is already in one of the tables.
3197c478bd9Sstevel@tonic-gate 	 * The mech_entry could be in another class.
3207c478bd9Sstevel@tonic-gate 	 */
3217c478bd9Sstevel@tonic-gate 	mutex_enter(&kcf_mech_tabs_lock);
3226f3f1c68Skrishna 	mt = kcf_mech_hash_find(mechname);
3237c478bd9Sstevel@tonic-gate 	if (mt != CRYPTO_MECH_INVALID) {
3247c478bd9Sstevel@tonic-gate 		/* Nothing to do, regardless the suggested class. */
3257c478bd9Sstevel@tonic-gate 		mutex_exit(&kcf_mech_tabs_lock);
3267c478bd9Sstevel@tonic-gate 		return (KCF_SUCCESS);
3277c478bd9Sstevel@tonic-gate 	}
3287c478bd9Sstevel@tonic-gate 	/* Now take the next unused mech entry in the class's tab */
3297c478bd9Sstevel@tonic-gate 	me_tab = kcf_mech_tabs_tab[class].met_tab;
3307c478bd9Sstevel@tonic-gate 	size = kcf_mech_tabs_tab[class].met_size;
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 	while (i < size) {
333ef56a3c5SKrishna Yenduri 		ME_MUTEXES_ENTER_ALL();
3347c478bd9Sstevel@tonic-gate 		if (me_tab[i].me_name[0] == 0) {
3357c478bd9Sstevel@tonic-gate 			/* Found an empty spot */
3367c478bd9Sstevel@tonic-gate 			(void) strncpy(me_tab[i].me_name, mechname,
3377c478bd9Sstevel@tonic-gate 			    CRYPTO_MAX_MECH_NAME);
3387c478bd9Sstevel@tonic-gate 			me_tab[i].me_name[CRYPTO_MAX_MECH_NAME-1] = '\0';
3396f3f1c68Skrishna 			me_tab[i].me_mechid = KCF_MECHID(class, i);
3407c478bd9Sstevel@tonic-gate 			/*
3417c478bd9Sstevel@tonic-gate 			 * No a-priori information about the new mechanism, so
3427c478bd9Sstevel@tonic-gate 			 * the threshold is set to zero.
3437c478bd9Sstevel@tonic-gate 			 */
3447c478bd9Sstevel@tonic-gate 			me_tab[i].me_threshold = 0;
3457c478bd9Sstevel@tonic-gate 
346ef56a3c5SKrishna Yenduri 			ME_MUTEXES_EXIT_ALL();
3476f3f1c68Skrishna 			/* Add the new mechanism to the hash table */
3486f3f1c68Skrishna 			(void) mod_hash_insert(kcf_mech_hash,
3496f3f1c68Skrishna 			    (mod_hash_key_t)me_tab[i].me_name,
3506f3f1c68Skrishna 			    (mod_hash_val_t)&(me_tab[i].me_mechid));
3517c478bd9Sstevel@tonic-gate 			break;
3527c478bd9Sstevel@tonic-gate 		}
353ef56a3c5SKrishna Yenduri 		ME_MUTEXES_EXIT_ALL();
3547c478bd9Sstevel@tonic-gate 		i++;
3557c478bd9Sstevel@tonic-gate 	}
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate 	mutex_exit(&kcf_mech_tabs_lock);
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate 	if (i == size) {
3607c478bd9Sstevel@tonic-gate 		return (KCF_MECH_TAB_FULL);
3617c478bd9Sstevel@tonic-gate 	}
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 	return (KCF_SUCCESS);
3647c478bd9Sstevel@tonic-gate }
3657c478bd9Sstevel@tonic-gate 
3667c478bd9Sstevel@tonic-gate /*
3677c478bd9Sstevel@tonic-gate  * kcf_add_mech_provider()
3687c478bd9Sstevel@tonic-gate  *
3697c478bd9Sstevel@tonic-gate  * Arguments:
3706a1073f8Skrishna  *	. An index in to  the provider mechanism array
3717c478bd9Sstevel@tonic-gate  *      . A pointer to the provider descriptor
3727c478bd9Sstevel@tonic-gate  *	. A storage for the kcf_prov_mech_desc_t the entry was added at.
3737c478bd9Sstevel@tonic-gate  *
3747c478bd9Sstevel@tonic-gate  * Description:
3757c478bd9Sstevel@tonic-gate  *      Adds  a new provider of a mechanism to the mechanism's mech_entry
3767c478bd9Sstevel@tonic-gate  *	chain.
3777c478bd9Sstevel@tonic-gate  *
3787c478bd9Sstevel@tonic-gate  * Context:
3797c478bd9Sstevel@tonic-gate  *      User context only.
3807c478bd9Sstevel@tonic-gate  *
3817c478bd9Sstevel@tonic-gate  * Returns
3827c478bd9Sstevel@tonic-gate  *      KCF_SUCCESS on success
3837c478bd9Sstevel@tonic-gate  *      KCF_MECH_TAB_FULL otherwise.
3847c478bd9Sstevel@tonic-gate  */
3857c478bd9Sstevel@tonic-gate int
kcf_add_mech_provider(short mech_indx,kcf_provider_desc_t * prov_desc,kcf_prov_mech_desc_t ** pmdpp)3866a1073f8Skrishna kcf_add_mech_provider(short mech_indx,
3877c478bd9Sstevel@tonic-gate     kcf_provider_desc_t *prov_desc, kcf_prov_mech_desc_t **pmdpp)
3887c478bd9Sstevel@tonic-gate {
3897c478bd9Sstevel@tonic-gate 	int error;
3907c478bd9Sstevel@tonic-gate 	kcf_mech_entry_t *mech_entry;
3916a1073f8Skrishna 	crypto_mech_info_t *mech_info;
3927c478bd9Sstevel@tonic-gate 	crypto_mech_type_t kcf_mech_type, mt;
3937c478bd9Sstevel@tonic-gate 	kcf_prov_mech_desc_t *prov_mech, *prov_mech2;
3947c478bd9Sstevel@tonic-gate 	crypto_func_group_t simple_fg_mask, dual_fg_mask;
3957c478bd9Sstevel@tonic-gate 	crypto_mech_info_t *dmi;
3967c478bd9Sstevel@tonic-gate 	crypto_mech_info_list_t *mil, *mil2;
3977c478bd9Sstevel@tonic-gate 	kcf_mech_entry_t *me;
3987c478bd9Sstevel@tonic-gate 	int i;
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 	ASSERT(prov_desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
4017c478bd9Sstevel@tonic-gate 
4026a1073f8Skrishna 	mech_info = &prov_desc->pd_mechanisms[mech_indx];
4037c478bd9Sstevel@tonic-gate 	/*
4047c478bd9Sstevel@tonic-gate 	 * Do not use the provider for the mechanism if
4057c478bd9Sstevel@tonic-gate 	 * policy does not allow it.
4067c478bd9Sstevel@tonic-gate 	 */
4077c478bd9Sstevel@tonic-gate 	if (is_mech_disabled(prov_desc, mech_info->cm_mech_name)) {
4087c478bd9Sstevel@tonic-gate 		*pmdpp = NULL;
4097c478bd9Sstevel@tonic-gate 		return (KCF_SUCCESS);
4107c478bd9Sstevel@tonic-gate 	}
4117c478bd9Sstevel@tonic-gate 
4127c478bd9Sstevel@tonic-gate 	/*
4137c478bd9Sstevel@tonic-gate 	 * A mechanism belongs to exactly one mechanism table.
4147c478bd9Sstevel@tonic-gate 	 * Find the class corresponding to the function group flag of
4157c478bd9Sstevel@tonic-gate 	 * the mechanism.
4167c478bd9Sstevel@tonic-gate 	 */
4176f3f1c68Skrishna 	kcf_mech_type = kcf_mech_hash_find(mech_info->cm_mech_name);
4187c478bd9Sstevel@tonic-gate 	if (kcf_mech_type == CRYPTO_MECH_INVALID) {
4197c478bd9Sstevel@tonic-gate 		crypto_func_group_t fg = mech_info->cm_func_group_mask;
4207c478bd9Sstevel@tonic-gate 		kcf_ops_class_t class;
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate 		if (fg & CRYPTO_FG_DIGEST || fg & CRYPTO_FG_DIGEST_ATOMIC)
4237c478bd9Sstevel@tonic-gate 			class = KCF_DIGEST_CLASS;
4247c478bd9Sstevel@tonic-gate 		else if (fg & CRYPTO_FG_ENCRYPT || fg & CRYPTO_FG_DECRYPT ||
4257c478bd9Sstevel@tonic-gate 		    fg & CRYPTO_FG_ENCRYPT_ATOMIC ||
4267c478bd9Sstevel@tonic-gate 		    fg & CRYPTO_FG_DECRYPT_ATOMIC)
4277c478bd9Sstevel@tonic-gate 			class = KCF_CIPHER_CLASS;
4287c478bd9Sstevel@tonic-gate 		else if (fg & CRYPTO_FG_MAC || fg & CRYPTO_FG_MAC_ATOMIC)
4297c478bd9Sstevel@tonic-gate 			class = KCF_MAC_CLASS;
4307c478bd9Sstevel@tonic-gate 		else if (fg & CRYPTO_FG_SIGN || fg & CRYPTO_FG_VERIFY ||
4317c478bd9Sstevel@tonic-gate 		    fg & CRYPTO_FG_SIGN_ATOMIC ||
4327c478bd9Sstevel@tonic-gate 		    fg & CRYPTO_FG_VERIFY_ATOMIC ||
4337c478bd9Sstevel@tonic-gate 		    fg & CRYPTO_FG_SIGN_RECOVER ||
4347c478bd9Sstevel@tonic-gate 		    fg & CRYPTO_FG_VERIFY_RECOVER)
4357c478bd9Sstevel@tonic-gate 			class = KCF_SIGN_CLASS;
4367c478bd9Sstevel@tonic-gate 		else if (fg & CRYPTO_FG_GENERATE ||
4377c478bd9Sstevel@tonic-gate 		    fg & CRYPTO_FG_GENERATE_KEY_PAIR ||
4387c478bd9Sstevel@tonic-gate 		    fg & CRYPTO_FG_WRAP || fg & CRYPTO_FG_UNWRAP ||
4397c478bd9Sstevel@tonic-gate 		    fg & CRYPTO_FG_DERIVE)
4407c478bd9Sstevel@tonic-gate 			class = KCF_KEYOPS_CLASS;
4417c478bd9Sstevel@tonic-gate 		else
4427c478bd9Sstevel@tonic-gate 			class = KCF_MISC_CLASS;
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate 		/*
4457c478bd9Sstevel@tonic-gate 		 * Attempt to create a new mech_entry for the specified
4467c478bd9Sstevel@tonic-gate 		 * mechanism. kcf_create_mech_entry() can handle the case
4477c478bd9Sstevel@tonic-gate 		 * where such an entry already exists.
4487c478bd9Sstevel@tonic-gate 		 */
4497c478bd9Sstevel@tonic-gate 		if ((error = kcf_create_mech_entry(class,
4507c478bd9Sstevel@tonic-gate 		    mech_info->cm_mech_name)) != KCF_SUCCESS) {
4517c478bd9Sstevel@tonic-gate 			return (error);
4527c478bd9Sstevel@tonic-gate 		}
4537c478bd9Sstevel@tonic-gate 		/* get the KCF mech type that was assigned to the mechanism */
4546f3f1c68Skrishna 		kcf_mech_type = kcf_mech_hash_find(mech_info->cm_mech_name);
4557c478bd9Sstevel@tonic-gate 		ASSERT(kcf_mech_type != CRYPTO_MECH_INVALID);
4567c478bd9Sstevel@tonic-gate 	}
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate 	error = kcf_get_mech_entry(kcf_mech_type, &mech_entry);
4597c478bd9Sstevel@tonic-gate 	ASSERT(error == KCF_SUCCESS);
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate 	/* allocate and initialize new kcf_prov_mech_desc */
4627c478bd9Sstevel@tonic-gate 	prov_mech = kmem_zalloc(sizeof (kcf_prov_mech_desc_t), KM_SLEEP);
4637c478bd9Sstevel@tonic-gate 	bcopy(mech_info, &prov_mech->pm_mech_info, sizeof (crypto_mech_info_t));
4647c478bd9Sstevel@tonic-gate 	prov_mech->pm_prov_desc = prov_desc;
4656a1073f8Skrishna 	prov_desc->pd_mech_indx[KCF_MECH2CLASS(kcf_mech_type)]
4666a1073f8Skrishna 	    [KCF_MECH2INDEX(kcf_mech_type)] = mech_indx;
4676a1073f8Skrishna 
4687c478bd9Sstevel@tonic-gate 	KCF_PROV_REFHOLD(prov_desc);
4697c478bd9Sstevel@tonic-gate 
4707c478bd9Sstevel@tonic-gate 	dual_fg_mask = mech_info->cm_func_group_mask & CRYPTO_FG_DUAL_MASK;
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 	if (dual_fg_mask == ((crypto_func_group_t)0))
4737c478bd9Sstevel@tonic-gate 		goto add_entry;
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 	simple_fg_mask = mech_info->cm_func_group_mask &
476ac129f9eSKrishna Yenduri 	    CRYPTO_FG_SIMPLEOP_MASK | CRYPTO_FG_RANDOM;
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate 	for (i = 0; i < prov_desc->pd_mech_list_count; i++) {
4797c478bd9Sstevel@tonic-gate 		dmi = &prov_desc->pd_mechanisms[i];
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate 		/* skip self */
4827c478bd9Sstevel@tonic-gate 		if (dmi->cm_mech_number == mech_info->cm_mech_number)
4837c478bd9Sstevel@tonic-gate 			continue;
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate 		/* skip if policy doesn't allow mechanism */
4867c478bd9Sstevel@tonic-gate 		if (is_mech_disabled(prov_desc, dmi->cm_mech_name))
4877c478bd9Sstevel@tonic-gate 			continue;
4887c478bd9Sstevel@tonic-gate 
4897c478bd9Sstevel@tonic-gate 		/* skip if not a dual operation mechanism */
4907c478bd9Sstevel@tonic-gate 		if (!(dmi->cm_func_group_mask & dual_fg_mask) ||
4917c478bd9Sstevel@tonic-gate 		    (dmi->cm_func_group_mask & simple_fg_mask))
4927c478bd9Sstevel@tonic-gate 			continue;
4937c478bd9Sstevel@tonic-gate 
4946f3f1c68Skrishna 		mt = kcf_mech_hash_find(dmi->cm_mech_name);
4957c478bd9Sstevel@tonic-gate 		if (mt == CRYPTO_MECH_INVALID)
4967c478bd9Sstevel@tonic-gate 			continue;
4977c478bd9Sstevel@tonic-gate 
4987c478bd9Sstevel@tonic-gate 		if (kcf_get_mech_entry(mt, &me) != KCF_SUCCESS)
4997c478bd9Sstevel@tonic-gate 			continue;
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate 		mil = kmem_zalloc(sizeof (*mil), KM_SLEEP);
5027c478bd9Sstevel@tonic-gate 		mil2 = kmem_zalloc(sizeof (*mil2), KM_SLEEP);
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate 		/*
5057c478bd9Sstevel@tonic-gate 		 * Ignore hard-coded entries in the mech table
5067c478bd9Sstevel@tonic-gate 		 * if the provider hasn't registered.
5077c478bd9Sstevel@tonic-gate 		 */
508ef56a3c5SKrishna Yenduri 		ME_MUTEXES_ENTER_ALL();
5097c478bd9Sstevel@tonic-gate 		if (me->me_hw_prov_chain == NULL && me->me_sw_prov == NULL) {
510ef56a3c5SKrishna Yenduri 			ME_MUTEXES_EXIT_ALL();
5117c478bd9Sstevel@tonic-gate 			kmem_free(mil, sizeof (*mil));
5127c478bd9Sstevel@tonic-gate 			kmem_free(mil2, sizeof (*mil2));
5137c478bd9Sstevel@tonic-gate 			continue;
5147c478bd9Sstevel@tonic-gate 		}
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate 		/*
5177c478bd9Sstevel@tonic-gate 		 * Add other dual mechanisms that have registered
5187c478bd9Sstevel@tonic-gate 		 * with the framework to this mechanism's
5197c478bd9Sstevel@tonic-gate 		 * cross-reference list.
5207c478bd9Sstevel@tonic-gate 		 */
5217c478bd9Sstevel@tonic-gate 		mil->ml_mech_info = *dmi; /* struct assignment */
5227c478bd9Sstevel@tonic-gate 		mil->ml_kcf_mechid = mt;
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate 		/* add to head of list */
5257c478bd9Sstevel@tonic-gate 		mil->ml_next = prov_mech->pm_mi_list;
5267c478bd9Sstevel@tonic-gate 		prov_mech->pm_mi_list = mil;
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate 		if (prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER)
5297c478bd9Sstevel@tonic-gate 			prov_mech2 = me->me_hw_prov_chain;
5307c478bd9Sstevel@tonic-gate 		else
5317c478bd9Sstevel@tonic-gate 			prov_mech2 = me->me_sw_prov;
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate 		if (prov_mech2 == NULL) {
5347c478bd9Sstevel@tonic-gate 			kmem_free(mil2, sizeof (*mil2));
535ef56a3c5SKrishna Yenduri 			ME_MUTEXES_EXIT_ALL();
5367c478bd9Sstevel@tonic-gate 			continue;
5377c478bd9Sstevel@tonic-gate 		}
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate 		/*
5407c478bd9Sstevel@tonic-gate 		 * Update all other cross-reference lists by
5417c478bd9Sstevel@tonic-gate 		 * adding this new mechanism.
5427c478bd9Sstevel@tonic-gate 		 */
5437c478bd9Sstevel@tonic-gate 		while (prov_mech2 != NULL) {
5447c478bd9Sstevel@tonic-gate 			if (prov_mech2->pm_prov_desc == prov_desc) {
5457c478bd9Sstevel@tonic-gate 				/* struct assignment */
5467c478bd9Sstevel@tonic-gate 				mil2->ml_mech_info = *mech_info;
5477c478bd9Sstevel@tonic-gate 				mil2->ml_kcf_mechid = kcf_mech_type;
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate 				/* add to head of list */
5507c478bd9Sstevel@tonic-gate 				mil2->ml_next = prov_mech2->pm_mi_list;
5517c478bd9Sstevel@tonic-gate 				prov_mech2->pm_mi_list = mil2;
5527c478bd9Sstevel@tonic-gate 				break;
5537c478bd9Sstevel@tonic-gate 			}
5547c478bd9Sstevel@tonic-gate 			prov_mech2 = prov_mech2->pm_next;
5557c478bd9Sstevel@tonic-gate 		}
5567c478bd9Sstevel@tonic-gate 		if (prov_mech2 == NULL)
5577c478bd9Sstevel@tonic-gate 			kmem_free(mil2, sizeof (*mil2));
5587c478bd9Sstevel@tonic-gate 
559ef56a3c5SKrishna Yenduri 		ME_MUTEXES_EXIT_ALL();
5607c478bd9Sstevel@tonic-gate 	}
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate add_entry:
5637c478bd9Sstevel@tonic-gate 	/*
5647c478bd9Sstevel@tonic-gate 	 * Add new kcf_prov_mech_desc at the front of HW providers
5657c478bd9Sstevel@tonic-gate 	 * chain.
5667c478bd9Sstevel@tonic-gate 	 */
5677c478bd9Sstevel@tonic-gate 	switch (prov_desc->pd_prov_type) {
5687c478bd9Sstevel@tonic-gate 
5697c478bd9Sstevel@tonic-gate 	case CRYPTO_HW_PROVIDER:
570ef56a3c5SKrishna Yenduri 		ME_MUTEXES_ENTER_ALL();
5717c478bd9Sstevel@tonic-gate 		prov_mech->pm_me = mech_entry;
5727c478bd9Sstevel@tonic-gate 		prov_mech->pm_next = mech_entry->me_hw_prov_chain;
5737c478bd9Sstevel@tonic-gate 		mech_entry->me_hw_prov_chain = prov_mech;
5747c478bd9Sstevel@tonic-gate 		mech_entry->me_num_hwprov++;
575ef56a3c5SKrishna Yenduri 		ME_MUTEXES_EXIT_ALL();
5767c478bd9Sstevel@tonic-gate 		break;
5777c478bd9Sstevel@tonic-gate 
5787c478bd9Sstevel@tonic-gate 	case CRYPTO_SW_PROVIDER:
579ef56a3c5SKrishna Yenduri 		ME_MUTEXES_ENTER_ALL();
5807c478bd9Sstevel@tonic-gate 		if (mech_entry->me_sw_prov != NULL) {
5817c478bd9Sstevel@tonic-gate 			/*
5827c478bd9Sstevel@tonic-gate 			 * There is already a SW provider for this mechanism.
5837c478bd9Sstevel@tonic-gate 			 * Since we allow only one SW provider per mechanism,
5847c478bd9Sstevel@tonic-gate 			 * report this condition.
5857c478bd9Sstevel@tonic-gate 			 */
5867c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "The cryptographic software provider "
5877c478bd9Sstevel@tonic-gate 			    "\"%s\" will not be used for %s. The provider "
5887c478bd9Sstevel@tonic-gate 			    "\"%s\" will be used for this mechanism "
5897c478bd9Sstevel@tonic-gate 			    "instead.", prov_desc->pd_description,
5907c478bd9Sstevel@tonic-gate 			    mech_info->cm_mech_name,
5917c478bd9Sstevel@tonic-gate 			    mech_entry->me_sw_prov->pm_prov_desc->
592ac129f9eSKrishna Yenduri 			    pd_description);
5937c478bd9Sstevel@tonic-gate 			KCF_PROV_REFRELE(prov_desc);
5947c478bd9Sstevel@tonic-gate 			kmem_free(prov_mech, sizeof (kcf_prov_mech_desc_t));
5957c478bd9Sstevel@tonic-gate 			prov_mech = NULL;
5967c478bd9Sstevel@tonic-gate 		} else {
5977c478bd9Sstevel@tonic-gate 			/*
5987c478bd9Sstevel@tonic-gate 			 * Set the provider as the software provider for
5997c478bd9Sstevel@tonic-gate 			 * this mechanism.
6007c478bd9Sstevel@tonic-gate 			 */
6017c478bd9Sstevel@tonic-gate 			mech_entry->me_sw_prov = prov_mech;
6027c478bd9Sstevel@tonic-gate 
6037c478bd9Sstevel@tonic-gate 			/* We'll wrap around after 4 billion registrations! */
6047c478bd9Sstevel@tonic-gate 			mech_entry->me_gen_swprov = kcf_gen_swprov++;
6057c478bd9Sstevel@tonic-gate 		}
606ef56a3c5SKrishna Yenduri 		ME_MUTEXES_EXIT_ALL();
6077c478bd9Sstevel@tonic-gate 		break;
6087c478bd9Sstevel@tonic-gate 	}
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate 	*pmdpp = prov_mech;
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate 	return (KCF_SUCCESS);
6137c478bd9Sstevel@tonic-gate }
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate /*
6167c478bd9Sstevel@tonic-gate  * kcf_remove_mech_provider()
6177c478bd9Sstevel@tonic-gate  *
6187c478bd9Sstevel@tonic-gate  * Arguments:
6197c478bd9Sstevel@tonic-gate  *      . mech_name: the name of the mechanism.
6207c478bd9Sstevel@tonic-gate  *      . prov_desc: The provider descriptor
6217c478bd9Sstevel@tonic-gate  *
6227c478bd9Sstevel@tonic-gate  * Description:
6237c478bd9Sstevel@tonic-gate  *      Removes a provider from chain of provider descriptors.
6247c478bd9Sstevel@tonic-gate  *	The provider is made unavailable to kernel consumers for the specified
6257c478bd9Sstevel@tonic-gate  *	mechanism.
6267c478bd9Sstevel@tonic-gate  *
6277c478bd9Sstevel@tonic-gate  * Context:
6287c478bd9Sstevel@tonic-gate  *      User context only.
6297c478bd9Sstevel@tonic-gate  */
6307c478bd9Sstevel@tonic-gate void
kcf_remove_mech_provider(char * mech_name,kcf_provider_desc_t * prov_desc)6317c478bd9Sstevel@tonic-gate kcf_remove_mech_provider(char *mech_name, kcf_provider_desc_t *prov_desc)
6327c478bd9Sstevel@tonic-gate {
6337c478bd9Sstevel@tonic-gate 	crypto_mech_type_t mech_type;
6347c478bd9Sstevel@tonic-gate 	kcf_prov_mech_desc_t *prov_mech, *prov_chain;
6357c478bd9Sstevel@tonic-gate 	kcf_prov_mech_desc_t **prev_entry_next;
6367c478bd9Sstevel@tonic-gate 	kcf_mech_entry_t *mech_entry;
6377c478bd9Sstevel@tonic-gate 	crypto_mech_info_list_t *mil, *mil2, *next, **prev_next;
6387c478bd9Sstevel@tonic-gate 
6397c478bd9Sstevel@tonic-gate 	ASSERT(prov_desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER);
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate 	/* get the KCF mech type that was assigned to the mechanism */
6426f3f1c68Skrishna 	if ((mech_type = kcf_mech_hash_find(mech_name)) ==
6437c478bd9Sstevel@tonic-gate 	    CRYPTO_MECH_INVALID) {
6447c478bd9Sstevel@tonic-gate 		/*
6457c478bd9Sstevel@tonic-gate 		 * Provider was not allowed for this mech due to policy or
6467c478bd9Sstevel@tonic-gate 		 * configuration.
6477c478bd9Sstevel@tonic-gate 		 */
6487c478bd9Sstevel@tonic-gate 		return;
6497c478bd9Sstevel@tonic-gate 	}
6507c478bd9Sstevel@tonic-gate 
6517c478bd9Sstevel@tonic-gate 	/* get a ptr to the mech_entry that was created */
6527c478bd9Sstevel@tonic-gate 	if (kcf_get_mech_entry(mech_type, &mech_entry) != KCF_SUCCESS) {
6537c478bd9Sstevel@tonic-gate 		/*
6547c478bd9Sstevel@tonic-gate 		 * Provider was not allowed for this mech due to policy or
6557c478bd9Sstevel@tonic-gate 		 * configuration.
6567c478bd9Sstevel@tonic-gate 		 */
6577c478bd9Sstevel@tonic-gate 		return;
6587c478bd9Sstevel@tonic-gate 	}
6597c478bd9Sstevel@tonic-gate 
660ef56a3c5SKrishna Yenduri 	ME_MUTEXES_ENTER_ALL();
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 	switch (prov_desc->pd_prov_type) {
6637c478bd9Sstevel@tonic-gate 
6647c478bd9Sstevel@tonic-gate 	case CRYPTO_HW_PROVIDER:
6657c478bd9Sstevel@tonic-gate 		/* find the provider in the mech_entry chain */
6667c478bd9Sstevel@tonic-gate 		prev_entry_next = &mech_entry->me_hw_prov_chain;
6677c478bd9Sstevel@tonic-gate 		prov_mech = mech_entry->me_hw_prov_chain;
6687c478bd9Sstevel@tonic-gate 		while (prov_mech != NULL &&
6697c478bd9Sstevel@tonic-gate 		    prov_mech->pm_prov_desc != prov_desc) {
6707c478bd9Sstevel@tonic-gate 			prev_entry_next = &prov_mech->pm_next;
6717c478bd9Sstevel@tonic-gate 			prov_mech = prov_mech->pm_next;
6727c478bd9Sstevel@tonic-gate 		}
6737c478bd9Sstevel@tonic-gate 
6747c478bd9Sstevel@tonic-gate 		if (prov_mech == NULL) {
6757c478bd9Sstevel@tonic-gate 			/* entry not found, simply return */
676ef56a3c5SKrishna Yenduri 			ME_MUTEXES_EXIT_ALL();
6777c478bd9Sstevel@tonic-gate 			return;
6787c478bd9Sstevel@tonic-gate 		}
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate 		/* remove provider entry from mech_entry chain */
6817c478bd9Sstevel@tonic-gate 		*prev_entry_next = prov_mech->pm_next;
6827c478bd9Sstevel@tonic-gate 		ASSERT(mech_entry->me_num_hwprov > 0);
6837c478bd9Sstevel@tonic-gate 		mech_entry->me_num_hwprov--;
6847c478bd9Sstevel@tonic-gate 		break;
6857c478bd9Sstevel@tonic-gate 
6867c478bd9Sstevel@tonic-gate 	case CRYPTO_SW_PROVIDER:
6877c478bd9Sstevel@tonic-gate 		if (mech_entry->me_sw_prov == NULL ||
6887c478bd9Sstevel@tonic-gate 		    mech_entry->me_sw_prov->pm_prov_desc != prov_desc) {
6897c478bd9Sstevel@tonic-gate 			/* not the software provider for this mechanism */
690ef56a3c5SKrishna Yenduri 			ME_MUTEXES_EXIT_ALL();
6917c478bd9Sstevel@tonic-gate 			return;
6927c478bd9Sstevel@tonic-gate 		}
6937c478bd9Sstevel@tonic-gate 		prov_mech = mech_entry->me_sw_prov;
6947c478bd9Sstevel@tonic-gate 		mech_entry->me_sw_prov = NULL;
6957c478bd9Sstevel@tonic-gate 		break;
6967c478bd9Sstevel@tonic-gate 	}
6977c478bd9Sstevel@tonic-gate 
698ef56a3c5SKrishna Yenduri 	ME_MUTEXES_EXIT_ALL();
6997c478bd9Sstevel@tonic-gate 
7007c478bd9Sstevel@tonic-gate 	/* Free the dual ops cross-reference lists  */
7017c478bd9Sstevel@tonic-gate 	mil = prov_mech->pm_mi_list;
7027c478bd9Sstevel@tonic-gate 	while (mil != NULL) {
7037c478bd9Sstevel@tonic-gate 		next = mil->ml_next;
7047c478bd9Sstevel@tonic-gate 		if (kcf_get_mech_entry(mil->ml_kcf_mechid,
7057c478bd9Sstevel@tonic-gate 		    &mech_entry) != KCF_SUCCESS) {
7067c478bd9Sstevel@tonic-gate 			mil = next;
7077c478bd9Sstevel@tonic-gate 			continue;
7087c478bd9Sstevel@tonic-gate 		}
7097c478bd9Sstevel@tonic-gate 
710ef56a3c5SKrishna Yenduri 		ME_MUTEXES_ENTER_ALL();
7117c478bd9Sstevel@tonic-gate 		if (prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER)
7127c478bd9Sstevel@tonic-gate 			prov_chain = mech_entry->me_hw_prov_chain;
7137c478bd9Sstevel@tonic-gate 		else
7147c478bd9Sstevel@tonic-gate 			prov_chain = mech_entry->me_sw_prov;
7157c478bd9Sstevel@tonic-gate 
7167c478bd9Sstevel@tonic-gate 		while (prov_chain != NULL) {
7177c478bd9Sstevel@tonic-gate 			if (prov_chain->pm_prov_desc == prov_desc) {
7187c478bd9Sstevel@tonic-gate 				prev_next = &prov_chain->pm_mi_list;
7197c478bd9Sstevel@tonic-gate 				mil2 = prov_chain->pm_mi_list;
7207c478bd9Sstevel@tonic-gate 				while (mil2 != NULL &&
7217c478bd9Sstevel@tonic-gate 				    mil2->ml_kcf_mechid != mech_type) {
7227c478bd9Sstevel@tonic-gate 					prev_next = &mil2->ml_next;
7237c478bd9Sstevel@tonic-gate 					mil2 = mil2->ml_next;
7247c478bd9Sstevel@tonic-gate 				}
7257c478bd9Sstevel@tonic-gate 				if (mil2 != NULL) {
7267c478bd9Sstevel@tonic-gate 					*prev_next = mil2->ml_next;
7277c478bd9Sstevel@tonic-gate 					kmem_free(mil2, sizeof (*mil2));
7287c478bd9Sstevel@tonic-gate 				}
7297c478bd9Sstevel@tonic-gate 				break;
7307c478bd9Sstevel@tonic-gate 			}
7317c478bd9Sstevel@tonic-gate 			prov_chain = prov_chain->pm_next;
7327c478bd9Sstevel@tonic-gate 		}
7337c478bd9Sstevel@tonic-gate 
734ef56a3c5SKrishna Yenduri 		ME_MUTEXES_EXIT_ALL();
7357c478bd9Sstevel@tonic-gate 		kmem_free(mil, sizeof (crypto_mech_info_list_t));
7367c478bd9Sstevel@tonic-gate 		mil = next;
7377c478bd9Sstevel@tonic-gate 	}
7387c478bd9Sstevel@tonic-gate 
7397c478bd9Sstevel@tonic-gate 	/* free entry  */
7407c478bd9Sstevel@tonic-gate 	KCF_PROV_REFRELE(prov_mech->pm_prov_desc);
7417c478bd9Sstevel@tonic-gate 	kmem_free(prov_mech, sizeof (kcf_prov_mech_desc_t));
7427c478bd9Sstevel@tonic-gate }
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate /*
7457c478bd9Sstevel@tonic-gate  * kcf_get_mech_entry()
7467c478bd9Sstevel@tonic-gate  *
7477c478bd9Sstevel@tonic-gate  * Arguments:
7487c478bd9Sstevel@tonic-gate  *      . The framework mechanism type
7497c478bd9Sstevel@tonic-gate  *      . Storage for the mechanism entry
7507c478bd9Sstevel@tonic-gate  *
7517c478bd9Sstevel@tonic-gate  * Description:
7527c478bd9Sstevel@tonic-gate  *      Retrieves the mechanism entry for the mech.
7537c478bd9Sstevel@tonic-gate  *
7547c478bd9Sstevel@tonic-gate  * Context:
7557c478bd9Sstevel@tonic-gate  *      User and interrupt contexts.
7567c478bd9Sstevel@tonic-gate  *
7577c478bd9Sstevel@tonic-gate  * Returns:
7587c478bd9Sstevel@tonic-gate  *      KCF_MECHANISM_XXX appropriate error code.
7597c478bd9Sstevel@tonic-gate  *      KCF_SUCCESS otherwise.
7607c478bd9Sstevel@tonic-gate  */
7617c478bd9Sstevel@tonic-gate int
kcf_get_mech_entry(crypto_mech_type_t mech_type,kcf_mech_entry_t ** mep)7627c478bd9Sstevel@tonic-gate kcf_get_mech_entry(crypto_mech_type_t mech_type, kcf_mech_entry_t **mep)
7637c478bd9Sstevel@tonic-gate {
7647c478bd9Sstevel@tonic-gate 	kcf_ops_class_t		class;
7657c478bd9Sstevel@tonic-gate 	int			index;
7667c478bd9Sstevel@tonic-gate 	kcf_mech_entry_tab_t	*me_tab;
7677c478bd9Sstevel@tonic-gate 
7687c478bd9Sstevel@tonic-gate 	ASSERT(mep != NULL);
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate 	class = KCF_MECH2CLASS(mech_type);
7717c478bd9Sstevel@tonic-gate 
7727c478bd9Sstevel@tonic-gate 	if ((class < KCF_FIRST_OPSCLASS) || (class > KCF_LAST_OPSCLASS)) {
7737c478bd9Sstevel@tonic-gate 		/* the caller won't need to know it's an invalid class */
7747c478bd9Sstevel@tonic-gate 		return (KCF_INVALID_MECH_NUMBER);
7757c478bd9Sstevel@tonic-gate 	}
7767c478bd9Sstevel@tonic-gate 
7777c478bd9Sstevel@tonic-gate 	me_tab = &kcf_mech_tabs_tab[class];
7787c478bd9Sstevel@tonic-gate 	index = KCF_MECH2INDEX(mech_type);
7797c478bd9Sstevel@tonic-gate 
7807c478bd9Sstevel@tonic-gate 	if ((index < 0) || (index >= me_tab->met_size)) {
7817c478bd9Sstevel@tonic-gate 		return (KCF_INVALID_MECH_NUMBER);
7827c478bd9Sstevel@tonic-gate 	}
7837c478bd9Sstevel@tonic-gate 
7847c478bd9Sstevel@tonic-gate 	*mep = &((me_tab->met_tab)[index]);
7857c478bd9Sstevel@tonic-gate 
7867c478bd9Sstevel@tonic-gate 	return (KCF_SUCCESS);
7877c478bd9Sstevel@tonic-gate }
7887c478bd9Sstevel@tonic-gate 
7897c478bd9Sstevel@tonic-gate /*
7907c478bd9Sstevel@tonic-gate  * Returns TRUE if the provider is usable and the MOD_NOAUTOUNLOAD flag
7917c478bd9Sstevel@tonic-gate  * is set in the modctl structure.
7927c478bd9Sstevel@tonic-gate  */
7937c478bd9Sstevel@tonic-gate static boolean_t
auto_unload_flag_set(kcf_prov_mech_desc_t * pm)7947c478bd9Sstevel@tonic-gate auto_unload_flag_set(kcf_prov_mech_desc_t *pm)
7957c478bd9Sstevel@tonic-gate {
7967c478bd9Sstevel@tonic-gate 	kcf_provider_desc_t *pd;
7977c478bd9Sstevel@tonic-gate 	struct modctl *mp;
7987c478bd9Sstevel@tonic-gate 	boolean_t ret = B_FALSE;
7997c478bd9Sstevel@tonic-gate 
8007c478bd9Sstevel@tonic-gate 	if (pm != NULL) {
8017c478bd9Sstevel@tonic-gate 		pd = pm->pm_prov_desc;
8027c478bd9Sstevel@tonic-gate 		KCF_PROV_REFHOLD(pd);
8037c478bd9Sstevel@tonic-gate 
8047c478bd9Sstevel@tonic-gate 		if (KCF_IS_PROV_USABLE(pd)) {
8057c478bd9Sstevel@tonic-gate 			mp = pd->pd_mctlp;
8067c478bd9Sstevel@tonic-gate 			if (mp->mod_loadflags & MOD_NOAUTOUNLOAD) {
8077c478bd9Sstevel@tonic-gate 				ret = B_TRUE;
8087c478bd9Sstevel@tonic-gate 			}
8097c478bd9Sstevel@tonic-gate 		}
8107c478bd9Sstevel@tonic-gate 		KCF_PROV_REFRELE(pd);
8117c478bd9Sstevel@tonic-gate 	}
8127c478bd9Sstevel@tonic-gate 
8137c478bd9Sstevel@tonic-gate 	return (ret);
8147c478bd9Sstevel@tonic-gate }
8157c478bd9Sstevel@tonic-gate 
8167c478bd9Sstevel@tonic-gate /*
8176f3f1c68Skrishna  * Lookup the hash table for an entry that matches the mechname.
8186f3f1c68Skrishna  * If there are no hardware or software providers for the mechanism,
8196f3f1c68Skrishna  * but there is an unloaded software provider, this routine will attempt
8206f3f1c68Skrishna  * to load it.
8217c478bd9Sstevel@tonic-gate  *
8226f3f1c68Skrishna  * If the MOD_NOAUTOUNLOAD flag is not set, a software provider is
8236f3f1c68Skrishna  * in constant danger of being unloaded.  For consumers that call
8246f3f1c68Skrishna  * crypto_mech2id() only once, the provider will not be reloaded
8256f3f1c68Skrishna  * if it becomes unloaded.  If a provider gets loaded elsewhere
8266f3f1c68Skrishna  * without the MOD_NOAUTOUNLOAD flag being set, we set it now.
8277c478bd9Sstevel@tonic-gate  */
8287c478bd9Sstevel@tonic-gate crypto_mech_type_t
crypto_mech2id_common(char * mechname,boolean_t load_module)8297c478bd9Sstevel@tonic-gate crypto_mech2id_common(char *mechname, boolean_t load_module)
8307c478bd9Sstevel@tonic-gate {
8317c478bd9Sstevel@tonic-gate 	crypto_mech_type_t mt;
8326f3f1c68Skrishna 	kcf_mech_entry_t *me;
8336f3f1c68Skrishna 	int i;
8347c478bd9Sstevel@tonic-gate 	kcf_ops_class_t class;
8357c478bd9Sstevel@tonic-gate 	boolean_t second_time = B_FALSE;
8367c478bd9Sstevel@tonic-gate 	boolean_t try_to_load_software_provider = B_FALSE;
837ef56a3c5SKrishna Yenduri 	kcf_lock_withpad_t *mp;
8387c478bd9Sstevel@tonic-gate 
8397c478bd9Sstevel@tonic-gate try_again:
8406f3f1c68Skrishna 	mt = kcf_mech_hash_find(mechname);
8416f3f1c68Skrishna 	if (!load_module || second_time == B_TRUE || servicing_interrupt())
8426f3f1c68Skrishna 		return (mt);
8436f3f1c68Skrishna 
8446f3f1c68Skrishna 	if (mt != CRYPTO_MECH_INVALID) {
8456f3f1c68Skrishna 		class = KCF_MECH2CLASS(mt);
8466f3f1c68Skrishna 		i = KCF_MECH2INDEX(mt);
8476f3f1c68Skrishna 		me = &(kcf_mech_tabs_tab[class].met_tab[i]);
848ef56a3c5SKrishna Yenduri 		mp = &me_mutexes[CPU_SEQID];
849ef56a3c5SKrishna Yenduri 		mutex_enter(&mp->kl_lock);
850ef56a3c5SKrishna Yenduri 
8516f3f1c68Skrishna 		if (load_module && !auto_unload_flag_set(me->me_sw_prov)) {
8526f3f1c68Skrishna 			try_to_load_software_provider = B_TRUE;
8537c478bd9Sstevel@tonic-gate 		}
854ef56a3c5SKrishna Yenduri 		mutex_exit(&mp->kl_lock);
8557c478bd9Sstevel@tonic-gate 	}
8567c478bd9Sstevel@tonic-gate 
8577c478bd9Sstevel@tonic-gate 	if (mt == CRYPTO_MECH_INVALID || try_to_load_software_provider) {
8587c478bd9Sstevel@tonic-gate 		struct modctl *mcp;
8597c478bd9Sstevel@tonic-gate 		boolean_t load_again = B_FALSE;
8607c478bd9Sstevel@tonic-gate 		char *module_name;
8617c478bd9Sstevel@tonic-gate 		int module_name_size;
8627c478bd9Sstevel@tonic-gate 
8637c478bd9Sstevel@tonic-gate 		/* try to find a software provider for the mechanism */
8647c478bd9Sstevel@tonic-gate 		if (get_sw_provider_for_mech(mechname, &module_name)
8657c478bd9Sstevel@tonic-gate 		    != CRYPTO_SUCCESS) {
8667c478bd9Sstevel@tonic-gate 			/* mt may already be set for a hw provider */
8677c478bd9Sstevel@tonic-gate 			return (mt);
8687c478bd9Sstevel@tonic-gate 		}
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate 		module_name_size = strlen(module_name) + 1;
8717c478bd9Sstevel@tonic-gate 		if (modload("crypto", module_name) == -1 ||
8727c478bd9Sstevel@tonic-gate 		    (mcp = mod_hold_by_name(module_name)) == NULL) {
8737c478bd9Sstevel@tonic-gate 			kmem_free(module_name, module_name_size);
8747c478bd9Sstevel@tonic-gate 			/* mt may already be set for a hw provider */
8757c478bd9Sstevel@tonic-gate 			return (mt);
8767c478bd9Sstevel@tonic-gate 		}
8777c478bd9Sstevel@tonic-gate 
8787c478bd9Sstevel@tonic-gate 		mcp->mod_loadflags |= MOD_NOAUTOUNLOAD;
8797c478bd9Sstevel@tonic-gate 
8807c478bd9Sstevel@tonic-gate 		/* memory pressure may have unloaded the module */
8817c478bd9Sstevel@tonic-gate 		if (!mcp->mod_installed)
8827c478bd9Sstevel@tonic-gate 			load_again = B_TRUE;
8837c478bd9Sstevel@tonic-gate 		mod_release_mod(mcp);
8847c478bd9Sstevel@tonic-gate 
8857c478bd9Sstevel@tonic-gate 		if (load_again)
8867c478bd9Sstevel@tonic-gate 			(void) modload("crypto", module_name);
8877c478bd9Sstevel@tonic-gate 
8887c478bd9Sstevel@tonic-gate 		kmem_free(module_name, module_name_size);
8897c478bd9Sstevel@tonic-gate 
8907c478bd9Sstevel@tonic-gate 		/* mt may already be set for a hw provider */
8917c478bd9Sstevel@tonic-gate 		if (mt != CRYPTO_MECH_INVALID)
8927c478bd9Sstevel@tonic-gate 			return (mt);
8937c478bd9Sstevel@tonic-gate 
8947c478bd9Sstevel@tonic-gate 		/*
8957c478bd9Sstevel@tonic-gate 		 * Try again.  Should find a software provider in the
8967c478bd9Sstevel@tonic-gate 		 * table this time around.
8977c478bd9Sstevel@tonic-gate 		 */
8987c478bd9Sstevel@tonic-gate 		second_time = B_TRUE;
8997c478bd9Sstevel@tonic-gate 		goto try_again;
9007c478bd9Sstevel@tonic-gate 	}
9017c478bd9Sstevel@tonic-gate 
9027c478bd9Sstevel@tonic-gate 	return (mt);
9037c478bd9Sstevel@tonic-gate }
904