xref: /onnv-gate/usr/src/uts/common/crypto/spi/kcf_spi.c (revision 11304:3092d1e303d6)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
52800Skrishna  * Common Development and Distribution License (the "License").
62800Skrishna  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
229505SBhargava.Yenduri@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate  * This file is part of the core Kernel Cryptographic Framework.
280Sstevel@tonic-gate  * It implements the SPI functions exported to cryptographic
290Sstevel@tonic-gate  * providers.
300Sstevel@tonic-gate  */
310Sstevel@tonic-gate 
320Sstevel@tonic-gate #include <sys/ksynch.h>
330Sstevel@tonic-gate #include <sys/cmn_err.h>
340Sstevel@tonic-gate #include <sys/ddi.h>
350Sstevel@tonic-gate #include <sys/sunddi.h>
360Sstevel@tonic-gate #include <sys/modctl.h>
370Sstevel@tonic-gate #include <sys/crypto/common.h>
380Sstevel@tonic-gate #include <sys/crypto/impl.h>
390Sstevel@tonic-gate #include <sys/crypto/sched_impl.h>
400Sstevel@tonic-gate #include <sys/crypto/spi.h>
4110732SAnthony.Scarpino@Sun.COM #include <sys/crypto/ioctladmin.h>
420Sstevel@tonic-gate #include <sys/taskq.h>
430Sstevel@tonic-gate #include <sys/disp.h>
440Sstevel@tonic-gate #include <sys/kstat.h>
450Sstevel@tonic-gate #include <sys/policy.h>
464494Skrishna #include <sys/cpuvar.h>
470Sstevel@tonic-gate 
480Sstevel@tonic-gate /*
490Sstevel@tonic-gate  * minalloc and maxalloc values to be used for taskq_create().
500Sstevel@tonic-gate  */
514494Skrishna int crypto_taskq_threads = CRYPTO_TASKQ_THREADS;
520Sstevel@tonic-gate int crypto_taskq_minalloc = CYRPTO_TASKQ_MIN;
530Sstevel@tonic-gate int crypto_taskq_maxalloc = CRYPTO_TASKQ_MAX;
540Sstevel@tonic-gate 
550Sstevel@tonic-gate static void remove_provider(kcf_provider_desc_t *);
560Sstevel@tonic-gate static void process_logical_providers(crypto_provider_info_t *,
570Sstevel@tonic-gate     kcf_provider_desc_t *);
580Sstevel@tonic-gate static int init_prov_mechs(crypto_provider_info_t *, kcf_provider_desc_t *);
590Sstevel@tonic-gate static int kcf_prov_kstat_update(kstat_t *, int);
604373Skrishna static void undo_register_provider_extra(kcf_provider_desc_t *);
614373Skrishna static void delete_kstat(kcf_provider_desc_t *);
620Sstevel@tonic-gate 
630Sstevel@tonic-gate static kcf_prov_stats_t kcf_stats_ks_data_template = {
640Sstevel@tonic-gate 	{ "kcf_ops_total",		KSTAT_DATA_UINT64 },
650Sstevel@tonic-gate 	{ "kcf_ops_passed",		KSTAT_DATA_UINT64 },
660Sstevel@tonic-gate 	{ "kcf_ops_failed",		KSTAT_DATA_UINT64 },
670Sstevel@tonic-gate 	{ "kcf_ops_returned_busy",	KSTAT_DATA_UINT64 }
680Sstevel@tonic-gate };
690Sstevel@tonic-gate 
700Sstevel@tonic-gate #define	KCF_SPI_COPY_OPS(src, dst, ops) if ((src)->ops != NULL) \
710Sstevel@tonic-gate 	*((dst)->ops) = *((src)->ops);
720Sstevel@tonic-gate 
730Sstevel@tonic-gate /*
744219Smcpowers  * Copy an ops vector from src to dst. Used during provider registration
754219Smcpowers  * to copy the ops vector from the provider info structure to the
764219Smcpowers  * provider descriptor maintained by KCF.
774219Smcpowers  * Copying the ops vector specified by the provider is needed since the
784219Smcpowers  * framework does not require the provider info structure to be
794219Smcpowers  * persistent.
804219Smcpowers  */
814219Smcpowers static void
824219Smcpowers copy_ops_vector_v1(crypto_ops_t *src_ops, crypto_ops_t *dst_ops)
834219Smcpowers {
844219Smcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_control_ops);
854219Smcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_digest_ops);
864219Smcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_cipher_ops);
874219Smcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_mac_ops);
884219Smcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_sign_ops);
894219Smcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_verify_ops);
904219Smcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_dual_ops);
914219Smcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_dual_cipher_mac_ops);
924219Smcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_random_ops);
934219Smcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_session_ops);
944219Smcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_object_ops);
954219Smcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_key_ops);
964219Smcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_provider_ops);
974219Smcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_ctx_ops);
984219Smcpowers }
994219Smcpowers 
1004219Smcpowers static void
1014219Smcpowers copy_ops_vector_v2(crypto_ops_t *src_ops, crypto_ops_t *dst_ops)
1024219Smcpowers {
1034219Smcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_mech_ops);
1044219Smcpowers }
1054219Smcpowers 
1064219Smcpowers static void
1074219Smcpowers copy_ops_vector_v3(crypto_ops_t *src_ops, crypto_ops_t *dst_ops)
1084219Smcpowers {
1094219Smcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_nostore_key_ops);
1104219Smcpowers }
1114219Smcpowers 
11210732SAnthony.Scarpino@Sun.COM static void
11310732SAnthony.Scarpino@Sun.COM copy_ops_vector_v4(crypto_ops_t *src_ops, crypto_ops_t *dst_ops)
11410732SAnthony.Scarpino@Sun.COM {
11510732SAnthony.Scarpino@Sun.COM 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_fips140_ops);
11610732SAnthony.Scarpino@Sun.COM }
11710732SAnthony.Scarpino@Sun.COM 
1184219Smcpowers /*
1190Sstevel@tonic-gate  * This routine is used to add cryptographic providers to the KEF framework.
1200Sstevel@tonic-gate  * Providers pass a crypto_provider_info structure to crypto_register_provider()
1210Sstevel@tonic-gate  * and get back a handle.  The crypto_provider_info structure contains a
1220Sstevel@tonic-gate  * list of mechanisms supported by the provider and an ops vector containing
1230Sstevel@tonic-gate  * provider entry points.  Hardware providers call this routine in their attach
1240Sstevel@tonic-gate  * routines.  Software providers call this routine in their _init() routine.
1250Sstevel@tonic-gate  */
1260Sstevel@tonic-gate int
1270Sstevel@tonic-gate crypto_register_provider(crypto_provider_info_t *info,
1280Sstevel@tonic-gate     crypto_kcf_provider_handle_t *handle)
1290Sstevel@tonic-gate {
13010732SAnthony.Scarpino@Sun.COM 	int need_fips140_verify, need_verify = 1;
1310Sstevel@tonic-gate 	struct modctl *mcp;
1320Sstevel@tonic-gate 	char *name;
1330Sstevel@tonic-gate 	char ks_name[KSTAT_STRLEN];
1340Sstevel@tonic-gate 	kcf_provider_desc_t *prov_desc = NULL;
1350Sstevel@tonic-gate 	int ret = CRYPTO_ARGUMENTS_BAD;
1360Sstevel@tonic-gate 
13710732SAnthony.Scarpino@Sun.COM 	if (info->pi_interface_version > CRYPTO_SPI_VERSION_4)
1380Sstevel@tonic-gate 		return (CRYPTO_VERSION_MISMATCH);
1390Sstevel@tonic-gate 
1400Sstevel@tonic-gate 	/*
1410Sstevel@tonic-gate 	 * Check provider type, must be software, hardware, or logical.
1420Sstevel@tonic-gate 	 */
1430Sstevel@tonic-gate 	if (info->pi_provider_type != CRYPTO_HW_PROVIDER &&
1440Sstevel@tonic-gate 	    info->pi_provider_type != CRYPTO_SW_PROVIDER &&
1450Sstevel@tonic-gate 	    info->pi_provider_type != CRYPTO_LOGICAL_PROVIDER)
1460Sstevel@tonic-gate 		return (CRYPTO_ARGUMENTS_BAD);
1470Sstevel@tonic-gate 
1480Sstevel@tonic-gate 	/*
1490Sstevel@tonic-gate 	 * Allocate and initialize a new provider descriptor. We also
1500Sstevel@tonic-gate 	 * hold it and release it when done.
1510Sstevel@tonic-gate 	 */
1520Sstevel@tonic-gate 	prov_desc = kcf_alloc_provider_desc(info);
1530Sstevel@tonic-gate 	KCF_PROV_REFHOLD(prov_desc);
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate 	prov_desc->pd_prov_type = info->pi_provider_type;
1560Sstevel@tonic-gate 
1570Sstevel@tonic-gate 	/* provider-private handle, opaque to KCF */
1580Sstevel@tonic-gate 	prov_desc->pd_prov_handle = info->pi_provider_handle;
1590Sstevel@tonic-gate 
1600Sstevel@tonic-gate 	/* copy provider description string */
1610Sstevel@tonic-gate 	if (info->pi_provider_description != NULL) {
1620Sstevel@tonic-gate 		/*
1630Sstevel@tonic-gate 		 * pi_provider_descriptor is a string that can contain
1640Sstevel@tonic-gate 		 * up to CRYPTO_PROVIDER_DESCR_MAX_LEN + 1 characters
1650Sstevel@tonic-gate 		 * INCLUDING the terminating null character. A bcopy()
1660Sstevel@tonic-gate 		 * is necessary here as pd_description should not have
1670Sstevel@tonic-gate 		 * a null character. See comments in kcf_alloc_provider_desc()
1680Sstevel@tonic-gate 		 * for details on pd_description field.
1690Sstevel@tonic-gate 		 */
1700Sstevel@tonic-gate 		bcopy(info->pi_provider_description, prov_desc->pd_description,
1710Sstevel@tonic-gate 		    min(strlen(info->pi_provider_description),
1720Sstevel@tonic-gate 		    CRYPTO_PROVIDER_DESCR_MAX_LEN));
1730Sstevel@tonic-gate 	}
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate 	if (info->pi_provider_type != CRYPTO_LOGICAL_PROVIDER) {
1760Sstevel@tonic-gate 		if (info->pi_ops_vector == NULL) {
1774219Smcpowers 			goto bail;
1780Sstevel@tonic-gate 		}
179904Smcpowers 		copy_ops_vector_v1(info->pi_ops_vector,
180904Smcpowers 		    prov_desc->pd_ops_vector);
1814219Smcpowers 		if (info->pi_interface_version >= CRYPTO_SPI_VERSION_2) {
182904Smcpowers 			copy_ops_vector_v2(info->pi_ops_vector,
183904Smcpowers 			    prov_desc->pd_ops_vector);
184904Smcpowers 			prov_desc->pd_flags = info->pi_flags;
185904Smcpowers 		}
18610732SAnthony.Scarpino@Sun.COM 		if (info->pi_interface_version >= CRYPTO_SPI_VERSION_3) {
1874219Smcpowers 			copy_ops_vector_v3(info->pi_ops_vector,
1884219Smcpowers 			    prov_desc->pd_ops_vector);
1894219Smcpowers 		}
19010732SAnthony.Scarpino@Sun.COM 		if (info->pi_interface_version == CRYPTO_SPI_VERSION_4) {
19110732SAnthony.Scarpino@Sun.COM 			copy_ops_vector_v4(info->pi_ops_vector,
19210732SAnthony.Scarpino@Sun.COM 			    prov_desc->pd_ops_vector);
19310732SAnthony.Scarpino@Sun.COM 		}
1940Sstevel@tonic-gate 	}
1950Sstevel@tonic-gate 
1964219Smcpowers 	/* object_ops and nostore_key_ops are mutually exclusive */
1974219Smcpowers 	if (prov_desc->pd_ops_vector->co_object_ops &&
1984219Smcpowers 	    prov_desc->pd_ops_vector->co_nostore_key_ops) {
1994219Smcpowers 		goto bail;
2004219Smcpowers 	}
2010Sstevel@tonic-gate 	/*
2020Sstevel@tonic-gate 	 * For software providers, copy the module name and module ID.
2030Sstevel@tonic-gate 	 * For hardware providers, copy the driver name and instance.
2040Sstevel@tonic-gate 	 */
2050Sstevel@tonic-gate 	switch (info->pi_provider_type) {
2060Sstevel@tonic-gate 	case  CRYPTO_SW_PROVIDER:
2070Sstevel@tonic-gate 		if (info->pi_provider_dev.pd_sw == NULL)
2080Sstevel@tonic-gate 			goto bail;
2090Sstevel@tonic-gate 
2100Sstevel@tonic-gate 		if ((mcp = mod_getctl(info->pi_provider_dev.pd_sw)) == NULL)
2110Sstevel@tonic-gate 			goto bail;
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate 		prov_desc->pd_module_id = mcp->mod_id;
2140Sstevel@tonic-gate 		name = mcp->mod_modname;
2150Sstevel@tonic-gate 		break;
2160Sstevel@tonic-gate 
2170Sstevel@tonic-gate 	case CRYPTO_HW_PROVIDER:
2180Sstevel@tonic-gate 	case CRYPTO_LOGICAL_PROVIDER:
2190Sstevel@tonic-gate 		if (info->pi_provider_dev.pd_hw == NULL)
2200Sstevel@tonic-gate 			goto bail;
2210Sstevel@tonic-gate 
2220Sstevel@tonic-gate 		prov_desc->pd_instance =
2230Sstevel@tonic-gate 		    ddi_get_instance(info->pi_provider_dev.pd_hw);
2240Sstevel@tonic-gate 		name = (char *)ddi_driver_name(info->pi_provider_dev.pd_hw);
2250Sstevel@tonic-gate 		break;
2260Sstevel@tonic-gate 	}
2270Sstevel@tonic-gate 	if (name == NULL)
2280Sstevel@tonic-gate 		goto bail;
2290Sstevel@tonic-gate 
2300Sstevel@tonic-gate 	prov_desc->pd_name = kmem_alloc(strlen(name) + 1, KM_SLEEP);
2310Sstevel@tonic-gate 	(void) strcpy(prov_desc->pd_name, name);
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate 	if ((prov_desc->pd_mctlp = kcf_get_modctl(info)) == NULL)
2340Sstevel@tonic-gate 		goto bail;
2350Sstevel@tonic-gate 
2360Sstevel@tonic-gate 	/* process the mechanisms supported by the provider */
2370Sstevel@tonic-gate 	if ((ret = init_prov_mechs(info, prov_desc)) != CRYPTO_SUCCESS)
2380Sstevel@tonic-gate 		goto bail;
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate 	/*
2410Sstevel@tonic-gate 	 * Add provider to providers tables, also sets the descriptor
2420Sstevel@tonic-gate 	 * pd_prov_id field.
2430Sstevel@tonic-gate 	 */
2440Sstevel@tonic-gate 	if ((ret = kcf_prov_tab_add_provider(prov_desc)) != CRYPTO_SUCCESS) {
2450Sstevel@tonic-gate 		undo_register_provider(prov_desc, B_FALSE);
2460Sstevel@tonic-gate 		goto bail;
2470Sstevel@tonic-gate 	}
2480Sstevel@tonic-gate 
2494373Skrishna 	if ((need_verify = kcf_need_signature_verification(prov_desc)) == -1) {
2504373Skrishna 		undo_register_provider(prov_desc, B_TRUE);
2514373Skrishna 		ret = CRYPTO_MODVERIFICATION_FAILED;
2524373Skrishna 		goto bail;
2530Sstevel@tonic-gate 	}
2540Sstevel@tonic-gate 
25510732SAnthony.Scarpino@Sun.COM 	if ((need_fips140_verify =
25610732SAnthony.Scarpino@Sun.COM 	    kcf_need_fips140_verification(prov_desc)) == -1) {
25710732SAnthony.Scarpino@Sun.COM 		mutex_enter(&prov_desc->pd_lock);
25810732SAnthony.Scarpino@Sun.COM 		prov_desc->pd_state = KCF_PROV_VERIFICATION_FAILED;
25910732SAnthony.Scarpino@Sun.COM 		mutex_exit(&prov_desc->pd_lock);
26010732SAnthony.Scarpino@Sun.COM 		ret = CRYPTO_FIPS140_ERROR;
26110732SAnthony.Scarpino@Sun.COM 		goto bail;
26210732SAnthony.Scarpino@Sun.COM 	}
26310732SAnthony.Scarpino@Sun.COM 
2640Sstevel@tonic-gate 	/*
2650Sstevel@tonic-gate 	 * We create a taskq only for a hardware provider. The global
2664494Skrishna 	 * software queue is used for software providers. We handle ordering
2674494Skrishna 	 * of multi-part requests in the taskq routine. So, it is safe to
2684494Skrishna 	 * have multiple threads for the taskq. We pass TASKQ_PREPOPULATE flag
2694494Skrishna 	 * to keep some entries cached to improve performance.
2700Sstevel@tonic-gate 	 */
2710Sstevel@tonic-gate 	if (prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER)
2729505SBhargava.Yenduri@Sun.COM 		prov_desc->pd_taskq = taskq_create("kcf_taskq",
2734494Skrishna 		    crypto_taskq_threads, minclsyspri,
2744494Skrishna 		    crypto_taskq_minalloc, crypto_taskq_maxalloc,
2754494Skrishna 		    TASKQ_PREPOPULATE);
2760Sstevel@tonic-gate 	else
2779505SBhargava.Yenduri@Sun.COM 		prov_desc->pd_taskq = NULL;
2780Sstevel@tonic-gate 
279*11304SJanie.Lu@Sun.COM 	/* no kernel session to logical providers and no pd_flags  */
2800Sstevel@tonic-gate 	if (prov_desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) {
2810Sstevel@tonic-gate 		/*
2820Sstevel@tonic-gate 		 * Open a session for session-oriented providers. This session
2830Sstevel@tonic-gate 		 * is used for all kernel consumers. This is fine as a provider
2840Sstevel@tonic-gate 		 * is required to support multiple thread access to a session.
2850Sstevel@tonic-gate 		 * We can do this only after the taskq has been created as we
2860Sstevel@tonic-gate 		 * do a kcf_submit_request() to open the session.
2870Sstevel@tonic-gate 		 */
2880Sstevel@tonic-gate 		if (KCF_PROV_SESSION_OPS(prov_desc) != NULL) {
2890Sstevel@tonic-gate 			kcf_req_params_t params;
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate 			KCF_WRAP_SESSION_OPS_PARAMS(&params,
2920Sstevel@tonic-gate 			    KCF_OP_SESSION_OPEN, &prov_desc->pd_sid, 0,
2930Sstevel@tonic-gate 			    CRYPTO_USER, NULL, 0, prov_desc);
2940Sstevel@tonic-gate 			ret = kcf_submit_request(prov_desc, NULL, NULL, &params,
2950Sstevel@tonic-gate 			    B_FALSE);
296*11304SJanie.Lu@Sun.COM 			if (ret != CRYPTO_SUCCESS)
297*11304SJanie.Lu@Sun.COM 				goto undo_then_bail;
298*11304SJanie.Lu@Sun.COM 		}
2990Sstevel@tonic-gate 
300*11304SJanie.Lu@Sun.COM 		/*
301*11304SJanie.Lu@Sun.COM 		 * Get the value for the maximum input length allowed if
302*11304SJanie.Lu@Sun.COM 		 * CRYPTO_HASH_NO_UPDATE or CRYPTO_HASH_NO_UPDATE is specified.
303*11304SJanie.Lu@Sun.COM 		 */
304*11304SJanie.Lu@Sun.COM 		if (prov_desc->pd_flags &
305*11304SJanie.Lu@Sun.COM 		    (CRYPTO_HASH_NO_UPDATE | CRYPTO_HMAC_NO_UPDATE)) {
306*11304SJanie.Lu@Sun.COM 			kcf_req_params_t params;
307*11304SJanie.Lu@Sun.COM 			crypto_provider_ext_info_t ext_info;
308*11304SJanie.Lu@Sun.COM 
309*11304SJanie.Lu@Sun.COM 			if (KCF_PROV_PROVMGMT_OPS(prov_desc) == NULL)
310*11304SJanie.Lu@Sun.COM 				goto undo_then_bail;
311*11304SJanie.Lu@Sun.COM 
312*11304SJanie.Lu@Sun.COM 			bzero(&ext_info, sizeof (ext_info));
313*11304SJanie.Lu@Sun.COM 			KCF_WRAP_PROVMGMT_OPS_PARAMS(&params,
314*11304SJanie.Lu@Sun.COM 			    KCF_OP_MGMT_EXTINFO,
315*11304SJanie.Lu@Sun.COM 			    0, NULL, 0, NULL, 0, NULL, &ext_info, prov_desc);
316*11304SJanie.Lu@Sun.COM 			ret = kcf_submit_request(prov_desc, NULL, NULL,
317*11304SJanie.Lu@Sun.COM 			    &params, B_FALSE);
318*11304SJanie.Lu@Sun.COM 			if (ret != CRYPTO_SUCCESS)
319*11304SJanie.Lu@Sun.COM 				goto undo_then_bail;
320*11304SJanie.Lu@Sun.COM 
321*11304SJanie.Lu@Sun.COM 			if (prov_desc->pd_flags & CRYPTO_HASH_NO_UPDATE) {
322*11304SJanie.Lu@Sun.COM 				prov_desc->pd_hash_limit =
323*11304SJanie.Lu@Sun.COM 				    ext_info.ei_hash_max_input_len;
324*11304SJanie.Lu@Sun.COM 			}
325*11304SJanie.Lu@Sun.COM 			if (prov_desc->pd_flags & CRYPTO_HMAC_NO_UPDATE) {
326*11304SJanie.Lu@Sun.COM 				prov_desc->pd_hmac_limit =
327*11304SJanie.Lu@Sun.COM 				    ext_info.ei_hmac_max_input_len;
3280Sstevel@tonic-gate 			}
3290Sstevel@tonic-gate 		}
3300Sstevel@tonic-gate 	}
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 	if (prov_desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) {
3330Sstevel@tonic-gate 		/*
3340Sstevel@tonic-gate 		 * Create the kstat for this provider. There is a kstat
3350Sstevel@tonic-gate 		 * installed for each successfully registered provider.
3360Sstevel@tonic-gate 		 * This kstat is deleted, when the provider unregisters.
3370Sstevel@tonic-gate 		 */
3380Sstevel@tonic-gate 		if (prov_desc->pd_prov_type == CRYPTO_SW_PROVIDER) {
3390Sstevel@tonic-gate 			(void) snprintf(ks_name, KSTAT_STRLEN, "%s_%s",
3400Sstevel@tonic-gate 			    prov_desc->pd_name, "provider_stats");
3410Sstevel@tonic-gate 		} else {
3420Sstevel@tonic-gate 			(void) snprintf(ks_name, KSTAT_STRLEN, "%s_%d_%u_%s",
3430Sstevel@tonic-gate 			    prov_desc->pd_name, prov_desc->pd_instance,
3440Sstevel@tonic-gate 			    prov_desc->pd_prov_id, "provider_stats");
3450Sstevel@tonic-gate 		}
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate 		prov_desc->pd_kstat = kstat_create("kcf", 0, ks_name, "crypto",
3480Sstevel@tonic-gate 		    KSTAT_TYPE_NAMED, sizeof (kcf_prov_stats_t) /
3490Sstevel@tonic-gate 		    sizeof (kstat_named_t), KSTAT_FLAG_VIRTUAL);
3500Sstevel@tonic-gate 
3510Sstevel@tonic-gate 		if (prov_desc->pd_kstat != NULL) {
3520Sstevel@tonic-gate 			bcopy(&kcf_stats_ks_data_template,
3530Sstevel@tonic-gate 			    &prov_desc->pd_ks_data,
3540Sstevel@tonic-gate 			    sizeof (kcf_stats_ks_data_template));
3550Sstevel@tonic-gate 			prov_desc->pd_kstat->ks_data = &prov_desc->pd_ks_data;
3560Sstevel@tonic-gate 			KCF_PROV_REFHOLD(prov_desc);
3570Sstevel@tonic-gate 			prov_desc->pd_kstat->ks_private = prov_desc;
3580Sstevel@tonic-gate 			prov_desc->pd_kstat->ks_update = kcf_prov_kstat_update;
3590Sstevel@tonic-gate 			kstat_install(prov_desc->pd_kstat);
3600Sstevel@tonic-gate 		}
3610Sstevel@tonic-gate 	}
3620Sstevel@tonic-gate 
3630Sstevel@tonic-gate 	if (prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER)
3640Sstevel@tonic-gate 		process_logical_providers(info, prov_desc);
3650Sstevel@tonic-gate 
36610732SAnthony.Scarpino@Sun.COM 	/* This provider needs to wait until we know the FIPS 140 status */
36710732SAnthony.Scarpino@Sun.COM 	if (need_fips140_verify == 1) {
36810732SAnthony.Scarpino@Sun.COM 		mutex_enter(&prov_desc->pd_lock);
36910732SAnthony.Scarpino@Sun.COM 		prov_desc->pd_state = KCF_PROV_UNVERIFIED_FIPS140;
37010732SAnthony.Scarpino@Sun.COM 		mutex_exit(&prov_desc->pd_lock);
37110732SAnthony.Scarpino@Sun.COM 		goto exit;
37210732SAnthony.Scarpino@Sun.COM 	}
37310732SAnthony.Scarpino@Sun.COM 
37410732SAnthony.Scarpino@Sun.COM 	/* This provider needs to have the signature verified */
3754373Skrishna 	if (need_verify == 1) {
37610732SAnthony.Scarpino@Sun.COM 		mutex_enter(&prov_desc->pd_lock);
37710732SAnthony.Scarpino@Sun.COM 		prov_desc->pd_state = KCF_PROV_UNVERIFIED;
37810732SAnthony.Scarpino@Sun.COM 		mutex_exit(&prov_desc->pd_lock);
37910732SAnthony.Scarpino@Sun.COM 
3809505SBhargava.Yenduri@Sun.COM 		/* kcf_verify_signature routine will release this hold */
3814373Skrishna 		KCF_PROV_REFHOLD(prov_desc);
3820Sstevel@tonic-gate 
3834373Skrishna 		if (prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER) {
3844373Skrishna 			/*
3854373Skrishna 			 * It is not safe to make the door upcall to kcfd from
3864373Skrishna 			 * this context since the kcfd thread could reenter
3874373Skrishna 			 * devfs. So, we dispatch a taskq job to do the
3884373Skrishna 			 * verification and return to the provider.
3894373Skrishna 			 */
3904373Skrishna 			(void) taskq_dispatch(system_taskq,
3914373Skrishna 			    kcf_verify_signature, (void *)prov_desc, TQ_SLEEP);
3924373Skrishna 		} else if (prov_desc->pd_prov_type == CRYPTO_SW_PROVIDER) {
3934373Skrishna 			kcf_verify_signature(prov_desc);
3944373Skrishna 			if (prov_desc->pd_state ==
3954373Skrishna 			    KCF_PROV_VERIFICATION_FAILED) {
3964373Skrishna 				undo_register_provider_extra(prov_desc);
3974373Skrishna 				ret = CRYPTO_MODVERIFICATION_FAILED;
3984373Skrishna 				goto bail;
3994373Skrishna 			}
4000Sstevel@tonic-gate 		}
4014373Skrishna 	} else {
4024373Skrishna 		mutex_enter(&prov_desc->pd_lock);
4034373Skrishna 		prov_desc->pd_state = KCF_PROV_READY;
4044373Skrishna 		mutex_exit(&prov_desc->pd_lock);
4054373Skrishna 		kcf_do_notify(prov_desc, B_TRUE);
4060Sstevel@tonic-gate 	}
4070Sstevel@tonic-gate 
40810732SAnthony.Scarpino@Sun.COM exit:
4090Sstevel@tonic-gate 	*handle = prov_desc->pd_kcf_prov_handle;
410*11304SJanie.Lu@Sun.COM 	KCF_PROV_REFRELE(prov_desc);
411*11304SJanie.Lu@Sun.COM 	return (CRYPTO_SUCCESS);
4120Sstevel@tonic-gate 
413*11304SJanie.Lu@Sun.COM undo_then_bail:
414*11304SJanie.Lu@Sun.COM 	undo_register_provider(prov_desc, B_TRUE);
415*11304SJanie.Lu@Sun.COM 	ret = CRYPTO_FAILED;
4160Sstevel@tonic-gate bail:
4170Sstevel@tonic-gate 	KCF_PROV_REFRELE(prov_desc);
4180Sstevel@tonic-gate 	return (ret);
4190Sstevel@tonic-gate }
4200Sstevel@tonic-gate 
4219505SBhargava.Yenduri@Sun.COM /* Return the number of holds on a provider. */
4229505SBhargava.Yenduri@Sun.COM int
4239505SBhargava.Yenduri@Sun.COM kcf_get_refcnt(kcf_provider_desc_t *pd, boolean_t do_lock)
4249505SBhargava.Yenduri@Sun.COM {
4259505SBhargava.Yenduri@Sun.COM 	int i;
4269505SBhargava.Yenduri@Sun.COM 	int refcnt = 0;
4279505SBhargava.Yenduri@Sun.COM 
4289505SBhargava.Yenduri@Sun.COM 	if (do_lock)
4299505SBhargava.Yenduri@Sun.COM 		for (i = 0; i < pd->pd_nbins; i++)
4309505SBhargava.Yenduri@Sun.COM 			mutex_enter(&(pd->pd_percpu_bins[i].kp_lock));
4319505SBhargava.Yenduri@Sun.COM 
4329505SBhargava.Yenduri@Sun.COM 	for (i = 0; i < pd->pd_nbins; i++)
4339505SBhargava.Yenduri@Sun.COM 		refcnt += pd->pd_percpu_bins[i].kp_holdcnt;
4349505SBhargava.Yenduri@Sun.COM 
4359505SBhargava.Yenduri@Sun.COM 	if (do_lock)
4369505SBhargava.Yenduri@Sun.COM 		for (i = 0; i < pd->pd_nbins; i++)
4379505SBhargava.Yenduri@Sun.COM 			mutex_exit(&(pd->pd_percpu_bins[i].kp_lock));
4389505SBhargava.Yenduri@Sun.COM 
4399505SBhargava.Yenduri@Sun.COM 	return (refcnt);
4409505SBhargava.Yenduri@Sun.COM }
4419505SBhargava.Yenduri@Sun.COM 
4420Sstevel@tonic-gate /*
4430Sstevel@tonic-gate  * This routine is used to notify the framework when a provider is being
4440Sstevel@tonic-gate  * removed.  Hardware providers call this routine in their detach routines.
4450Sstevel@tonic-gate  * Software providers call this routine in their _fini() routine.
4460Sstevel@tonic-gate  */
4470Sstevel@tonic-gate int
4480Sstevel@tonic-gate crypto_unregister_provider(crypto_kcf_provider_handle_t handle)
4490Sstevel@tonic-gate {
4500Sstevel@tonic-gate 	uint_t mech_idx;
4510Sstevel@tonic-gate 	kcf_provider_desc_t *desc;
4520Sstevel@tonic-gate 	kcf_prov_state_t saved_state;
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate 	/* lookup provider descriptor */
4550Sstevel@tonic-gate 	if ((desc = kcf_prov_tab_lookup((crypto_provider_id_t)handle)) == NULL)
4560Sstevel@tonic-gate 		return (CRYPTO_UNKNOWN_PROVIDER);
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 	mutex_enter(&desc->pd_lock);
4590Sstevel@tonic-gate 	/*
4600Sstevel@tonic-gate 	 * Check if any other thread is disabling or removing
4610Sstevel@tonic-gate 	 * this provider. We return if this is the case.
4620Sstevel@tonic-gate 	 */
4630Sstevel@tonic-gate 	if (desc->pd_state >= KCF_PROV_DISABLED) {
4640Sstevel@tonic-gate 		mutex_exit(&desc->pd_lock);
4650Sstevel@tonic-gate 		/* Release reference held by kcf_prov_tab_lookup(). */
4660Sstevel@tonic-gate 		KCF_PROV_REFRELE(desc);
4670Sstevel@tonic-gate 		return (CRYPTO_BUSY);
4680Sstevel@tonic-gate 	}
4690Sstevel@tonic-gate 
4700Sstevel@tonic-gate 	saved_state = desc->pd_state;
4719505SBhargava.Yenduri@Sun.COM 	desc->pd_state = KCF_PROV_UNREGISTERING;
4720Sstevel@tonic-gate 
4730Sstevel@tonic-gate 	if (saved_state == KCF_PROV_BUSY) {
4740Sstevel@tonic-gate 		/*
4754912Skrishna 		 * The per-provider taskq threads may be waiting. We
4764912Skrishna 		 * signal them so that they can start failing requests.
4770Sstevel@tonic-gate 		 */
4784912Skrishna 		cv_broadcast(&desc->pd_resume_cv);
4790Sstevel@tonic-gate 	}
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate 	mutex_exit(&desc->pd_lock);
4820Sstevel@tonic-gate 
4830Sstevel@tonic-gate 	if (desc->pd_prov_type != CRYPTO_SW_PROVIDER) {
4840Sstevel@tonic-gate 		remove_provider(desc);
4850Sstevel@tonic-gate 	}
4860Sstevel@tonic-gate 
4870Sstevel@tonic-gate 	if (desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) {
4880Sstevel@tonic-gate 		/* remove the provider from the mechanisms tables */
4890Sstevel@tonic-gate 		for (mech_idx = 0; mech_idx < desc->pd_mech_list_count;
4900Sstevel@tonic-gate 		    mech_idx++) {
4910Sstevel@tonic-gate 			kcf_remove_mech_provider(
4920Sstevel@tonic-gate 			    desc->pd_mechanisms[mech_idx].cm_mech_name, desc);
4930Sstevel@tonic-gate 		}
4940Sstevel@tonic-gate 	}
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate 	/* remove provider from providers table */
4970Sstevel@tonic-gate 	if (kcf_prov_tab_rem_provider((crypto_provider_id_t)handle) !=
4980Sstevel@tonic-gate 	    CRYPTO_SUCCESS) {
4990Sstevel@tonic-gate 		/* Release reference held by kcf_prov_tab_lookup(). */
5000Sstevel@tonic-gate 		KCF_PROV_REFRELE(desc);
5010Sstevel@tonic-gate 		return (CRYPTO_UNKNOWN_PROVIDER);
5020Sstevel@tonic-gate 	}
5030Sstevel@tonic-gate 
5044373Skrishna 	delete_kstat(desc);
5050Sstevel@tonic-gate 
5060Sstevel@tonic-gate 	if (desc->pd_prov_type == CRYPTO_SW_PROVIDER) {
5070Sstevel@tonic-gate 		/*
5089505SBhargava.Yenduri@Sun.COM 		 * Wait till the existing requests with the provider complete
5099505SBhargava.Yenduri@Sun.COM 		 * and all the holds are released. All the holds on a software
5109505SBhargava.Yenduri@Sun.COM 		 * provider are from kernel clients and the hold time
5119505SBhargava.Yenduri@Sun.COM 		 * is expected to be short. So, we won't be stuck here forever.
5120Sstevel@tonic-gate 		 */
5139505SBhargava.Yenduri@Sun.COM 		while (kcf_get_refcnt(desc, B_TRUE) > 1) {
5149505SBhargava.Yenduri@Sun.COM 			/* wait 1 second and try again. */
5159505SBhargava.Yenduri@Sun.COM 			delay(1 * drv_usectohz(1000000));
5169505SBhargava.Yenduri@Sun.COM 		}
5170Sstevel@tonic-gate 	} else {
5189505SBhargava.Yenduri@Sun.COM 		int i;
5199505SBhargava.Yenduri@Sun.COM 		kcf_prov_cpu_t *mp;
5209505SBhargava.Yenduri@Sun.COM 
5210Sstevel@tonic-gate 		/*
5220Sstevel@tonic-gate 		 * Wait until requests that have been sent to the provider
5230Sstevel@tonic-gate 		 * complete.
5240Sstevel@tonic-gate 		 */
5259505SBhargava.Yenduri@Sun.COM 		for (i = 0; i < desc->pd_nbins; i++) {
5269505SBhargava.Yenduri@Sun.COM 			mp = &(desc->pd_percpu_bins[i]);
5279505SBhargava.Yenduri@Sun.COM 
5289505SBhargava.Yenduri@Sun.COM 			mutex_enter(&mp->kp_lock);
5299505SBhargava.Yenduri@Sun.COM 			while (mp->kp_jobcnt > 0) {
5309505SBhargava.Yenduri@Sun.COM 				cv_wait(&mp->kp_cv, &mp->kp_lock);
5319505SBhargava.Yenduri@Sun.COM 			}
5329505SBhargava.Yenduri@Sun.COM 			mutex_exit(&mp->kp_lock);
5339505SBhargava.Yenduri@Sun.COM 		}
5340Sstevel@tonic-gate 	}
5350Sstevel@tonic-gate 
5369505SBhargava.Yenduri@Sun.COM 	mutex_enter(&desc->pd_lock);
5379505SBhargava.Yenduri@Sun.COM 	desc->pd_state = KCF_PROV_UNREGISTERED;
5389505SBhargava.Yenduri@Sun.COM 	mutex_exit(&desc->pd_lock);
5399505SBhargava.Yenduri@Sun.COM 
5404373Skrishna 	kcf_do_notify(desc, B_FALSE);
5412800Skrishna 
54210166SBhargava.Yenduri@Sun.COM 	mutex_enter(&prov_tab_mutex);
5439505SBhargava.Yenduri@Sun.COM 	/* Release reference held by kcf_prov_tab_lookup(). */
5449505SBhargava.Yenduri@Sun.COM 	KCF_PROV_REFRELE(desc);
5459505SBhargava.Yenduri@Sun.COM 
5469505SBhargava.Yenduri@Sun.COM 	if (kcf_get_refcnt(desc, B_TRUE) == 0) {
54710166SBhargava.Yenduri@Sun.COM 		/* kcf_free_provider_desc drops prov_tab_mutex */
5480Sstevel@tonic-gate 		kcf_free_provider_desc(desc);
5490Sstevel@tonic-gate 	} else {
5509505SBhargava.Yenduri@Sun.COM 		ASSERT(desc->pd_prov_type != CRYPTO_SW_PROVIDER);
5519505SBhargava.Yenduri@Sun.COM 		/*
5529505SBhargava.Yenduri@Sun.COM 		 * We could avoid this if /dev/crypto can proactively
5539505SBhargava.Yenduri@Sun.COM 		 * remove any holds on us from a dormant PKCS #11 app.
55410166SBhargava.Yenduri@Sun.COM 		 * For now, we check the provider table for
55510166SBhargava.Yenduri@Sun.COM 		 * KCF_PROV_UNREGISTERED entries when a provider is
55610166SBhargava.Yenduri@Sun.COM 		 * added to the table or when a provider is removed from it
55710166SBhargava.Yenduri@Sun.COM 		 * and free them when refcnt reaches zero.
5589505SBhargava.Yenduri@Sun.COM 		 */
5599505SBhargava.Yenduri@Sun.COM 		kcf_need_provtab_walk = B_TRUE;
5609505SBhargava.Yenduri@Sun.COM 		mutex_exit(&prov_tab_mutex);
5610Sstevel@tonic-gate 	}
5620Sstevel@tonic-gate 
5630Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
5640Sstevel@tonic-gate }
5650Sstevel@tonic-gate 
5660Sstevel@tonic-gate /*
5670Sstevel@tonic-gate  * This routine is used to notify the framework that the state of
5680Sstevel@tonic-gate  * a cryptographic provider has changed. Valid state codes are:
5690Sstevel@tonic-gate  *
5700Sstevel@tonic-gate  * CRYPTO_PROVIDER_READY
5710Sstevel@tonic-gate  * 	The provider indicates that it can process more requests. A provider
5720Sstevel@tonic-gate  *	will notify with this event if it previously has notified us with a
5730Sstevel@tonic-gate  *	CRYPTO_PROVIDER_BUSY.
5740Sstevel@tonic-gate  *
5750Sstevel@tonic-gate  * CRYPTO_PROVIDER_BUSY
5760Sstevel@tonic-gate  * 	The provider can not take more requests.
5770Sstevel@tonic-gate  *
5780Sstevel@tonic-gate  * CRYPTO_PROVIDER_FAILED
5790Sstevel@tonic-gate  *	The provider encountered an internal error. The framework will not
5800Sstevel@tonic-gate  * 	be sending any more requests to the provider. The provider may notify
5810Sstevel@tonic-gate  *	with a CRYPTO_PROVIDER_READY, if it is able to recover from the error.
5820Sstevel@tonic-gate  *
5830Sstevel@tonic-gate  * This routine can be called from user or interrupt context.
5840Sstevel@tonic-gate  */
5850Sstevel@tonic-gate void
5860Sstevel@tonic-gate crypto_provider_notification(crypto_kcf_provider_handle_t handle, uint_t state)
5870Sstevel@tonic-gate {
5880Sstevel@tonic-gate 	kcf_provider_desc_t *pd;
5890Sstevel@tonic-gate 
5900Sstevel@tonic-gate 	/* lookup the provider from the given handle */
5910Sstevel@tonic-gate 	if ((pd = kcf_prov_tab_lookup((crypto_provider_id_t)handle)) == NULL)
5920Sstevel@tonic-gate 		return;
5930Sstevel@tonic-gate 
5940Sstevel@tonic-gate 	mutex_enter(&pd->pd_lock);
5950Sstevel@tonic-gate 
5964373Skrishna 	if (pd->pd_state <= KCF_PROV_VERIFICATION_FAILED)
5974373Skrishna 		goto out;
5984373Skrishna 
5990Sstevel@tonic-gate 	if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
6000Sstevel@tonic-gate 		cmn_err(CE_WARN, "crypto_provider_notification: "
6010Sstevel@tonic-gate 		    "logical provider (%x) ignored\n", handle);
6020Sstevel@tonic-gate 		goto out;
6030Sstevel@tonic-gate 	}
6040Sstevel@tonic-gate 	switch (state) {
6050Sstevel@tonic-gate 	case CRYPTO_PROVIDER_READY:
6060Sstevel@tonic-gate 		switch (pd->pd_state) {
6070Sstevel@tonic-gate 		case KCF_PROV_BUSY:
6080Sstevel@tonic-gate 			pd->pd_state = KCF_PROV_READY;
6090Sstevel@tonic-gate 			/*
6104912Skrishna 			 * Signal the per-provider taskq threads that they
6114912Skrishna 			 * can start submitting requests.
6120Sstevel@tonic-gate 			 */
6134912Skrishna 			cv_broadcast(&pd->pd_resume_cv);
6140Sstevel@tonic-gate 			break;
6150Sstevel@tonic-gate 
6160Sstevel@tonic-gate 		case KCF_PROV_FAILED:
6170Sstevel@tonic-gate 			/*
6180Sstevel@tonic-gate 			 * The provider recovered from the error. Let us
6190Sstevel@tonic-gate 			 * use it now.
6200Sstevel@tonic-gate 			 */
6210Sstevel@tonic-gate 			pd->pd_state = KCF_PROV_READY;
6220Sstevel@tonic-gate 			break;
6230Sstevel@tonic-gate 		}
6240Sstevel@tonic-gate 		break;
6250Sstevel@tonic-gate 
6260Sstevel@tonic-gate 	case CRYPTO_PROVIDER_BUSY:
6270Sstevel@tonic-gate 		switch (pd->pd_state) {
6280Sstevel@tonic-gate 		case KCF_PROV_READY:
6290Sstevel@tonic-gate 			pd->pd_state = KCF_PROV_BUSY;
6300Sstevel@tonic-gate 			break;
6310Sstevel@tonic-gate 		}
6320Sstevel@tonic-gate 		break;
6330Sstevel@tonic-gate 
6340Sstevel@tonic-gate 	case CRYPTO_PROVIDER_FAILED:
6350Sstevel@tonic-gate 		/*
6360Sstevel@tonic-gate 		 * We note the failure and return. The per-provider taskq
6374912Skrishna 		 * threads check this flag and start failing the
6380Sstevel@tonic-gate 		 * requests, if it is set. See process_req_hwp() for details.
6390Sstevel@tonic-gate 		 */
6400Sstevel@tonic-gate 		switch (pd->pd_state) {
6410Sstevel@tonic-gate 		case KCF_PROV_READY:
6420Sstevel@tonic-gate 			pd->pd_state = KCF_PROV_FAILED;
6430Sstevel@tonic-gate 			break;
6440Sstevel@tonic-gate 
6450Sstevel@tonic-gate 		case KCF_PROV_BUSY:
6460Sstevel@tonic-gate 			pd->pd_state = KCF_PROV_FAILED;
6470Sstevel@tonic-gate 			/*
6484912Skrishna 			 * The per-provider taskq threads may be waiting. We
6494912Skrishna 			 * signal them so that they can start failing requests.
6500Sstevel@tonic-gate 			 */
6514912Skrishna 			cv_broadcast(&pd->pd_resume_cv);
6520Sstevel@tonic-gate 			break;
6530Sstevel@tonic-gate 		}
6540Sstevel@tonic-gate 		break;
6550Sstevel@tonic-gate 	}
6560Sstevel@tonic-gate out:
6570Sstevel@tonic-gate 	mutex_exit(&pd->pd_lock);
6580Sstevel@tonic-gate 	KCF_PROV_REFRELE(pd);
6590Sstevel@tonic-gate }
6600Sstevel@tonic-gate 
6610Sstevel@tonic-gate /*
6620Sstevel@tonic-gate  * This routine is used to notify the framework the result of
6630Sstevel@tonic-gate  * an asynchronous request handled by a provider. Valid error
6640Sstevel@tonic-gate  * codes are the same as the CRYPTO_* errors defined in common.h.
6650Sstevel@tonic-gate  *
6660Sstevel@tonic-gate  * This routine can be called from user or interrupt context.
6670Sstevel@tonic-gate  */
6680Sstevel@tonic-gate void
6690Sstevel@tonic-gate crypto_op_notification(crypto_req_handle_t handle, int error)
6700Sstevel@tonic-gate {
6710Sstevel@tonic-gate 	kcf_call_type_t ctype;
6720Sstevel@tonic-gate 
6738384SBhargava.Yenduri@Sun.COM 	if (handle == NULL)
6748384SBhargava.Yenduri@Sun.COM 		return;
6758384SBhargava.Yenduri@Sun.COM 
6760Sstevel@tonic-gate 	if ((ctype = GET_REQ_TYPE(handle)) == CRYPTO_SYNCH) {
6770Sstevel@tonic-gate 		kcf_sreq_node_t *sreq = (kcf_sreq_node_t *)handle;
6780Sstevel@tonic-gate 
6799505SBhargava.Yenduri@Sun.COM 		KCF_PROV_JOB_RELE_STAT(sreq->sn_mp, (error != CRYPTO_SUCCESS));
6800Sstevel@tonic-gate 		kcf_sop_done(sreq, error);
6810Sstevel@tonic-gate 	} else {
6820Sstevel@tonic-gate 		kcf_areq_node_t *areq = (kcf_areq_node_t *)handle;
6830Sstevel@tonic-gate 
6840Sstevel@tonic-gate 		ASSERT(ctype == CRYPTO_ASYNCH);
6859505SBhargava.Yenduri@Sun.COM 		KCF_PROV_JOB_RELE_STAT(areq->an_mp, (error != CRYPTO_SUCCESS));
6860Sstevel@tonic-gate 		kcf_aop_done(areq, error);
6870Sstevel@tonic-gate 	}
6880Sstevel@tonic-gate }
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate /*
6910Sstevel@tonic-gate  * This routine is used by software providers to determine
6920Sstevel@tonic-gate  * whether to use KM_SLEEP or KM_NOSLEEP during memory allocation.
6930Sstevel@tonic-gate  * Note that hardware providers can always use KM_SLEEP. So,
6940Sstevel@tonic-gate  * they do not need to call this routine.
6950Sstevel@tonic-gate  *
6960Sstevel@tonic-gate  * This routine can be called from user or interrupt context.
6970Sstevel@tonic-gate  */
6980Sstevel@tonic-gate int
6990Sstevel@tonic-gate crypto_kmflag(crypto_req_handle_t handle)
7000Sstevel@tonic-gate {
7010Sstevel@tonic-gate 	return (REQHNDL2_KMFLAG(handle));
7020Sstevel@tonic-gate }
7030Sstevel@tonic-gate 
7040Sstevel@tonic-gate /*
7050Sstevel@tonic-gate  * Process the mechanism info structures specified by the provider
7060Sstevel@tonic-gate  * during registration. A NULL crypto_provider_info_t indicates
7070Sstevel@tonic-gate  * an already initialized provider descriptor.
7080Sstevel@tonic-gate  *
7090Sstevel@tonic-gate  * Mechanisms are not added to the kernel's mechanism table if the
7100Sstevel@tonic-gate  * provider is a logical provider.
7110Sstevel@tonic-gate  *
7120Sstevel@tonic-gate  * Returns CRYPTO_SUCCESS on success, CRYPTO_ARGUMENTS if one
7130Sstevel@tonic-gate  * of the specified mechanisms was malformed, or CRYPTO_HOST_MEMORY
7140Sstevel@tonic-gate  * if the table of mechanisms is full.
7150Sstevel@tonic-gate  */
7160Sstevel@tonic-gate static int
7170Sstevel@tonic-gate init_prov_mechs(crypto_provider_info_t *info, kcf_provider_desc_t *desc)
7180Sstevel@tonic-gate {
7190Sstevel@tonic-gate 	uint_t mech_idx;
7200Sstevel@tonic-gate 	uint_t cleanup_idx;
7210Sstevel@tonic-gate 	int err = CRYPTO_SUCCESS;
7220Sstevel@tonic-gate 	kcf_prov_mech_desc_t *pmd;
7230Sstevel@tonic-gate 	int desc_use_count = 0;
7240Sstevel@tonic-gate 	int mcount = desc->pd_mech_list_count;
7250Sstevel@tonic-gate 
7260Sstevel@tonic-gate 	if (desc->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
7270Sstevel@tonic-gate 		if (info != NULL) {
7280Sstevel@tonic-gate 			ASSERT(info->pi_mechanisms != NULL);
7290Sstevel@tonic-gate 			bcopy(info->pi_mechanisms, desc->pd_mechanisms,
7300Sstevel@tonic-gate 			    sizeof (crypto_mech_info_t) * mcount);
7310Sstevel@tonic-gate 		}
7320Sstevel@tonic-gate 		return (CRYPTO_SUCCESS);
7330Sstevel@tonic-gate 	}
7340Sstevel@tonic-gate 
7350Sstevel@tonic-gate 	/*
7360Sstevel@tonic-gate 	 * Copy the mechanism list from the provider info to the provider
7370Sstevel@tonic-gate 	 * descriptor. desc->pd_mechanisms has an extra crypto_mech_info_t
7380Sstevel@tonic-gate 	 * element if the provider has random_ops since we keep an internal
7390Sstevel@tonic-gate 	 * mechanism, SUN_RANDOM, in this case.
7400Sstevel@tonic-gate 	 */
7410Sstevel@tonic-gate 	if (info != NULL) {
742904Smcpowers 		if (info->pi_ops_vector->co_random_ops != NULL) {
7430Sstevel@tonic-gate 			crypto_mech_info_t *rand_mi;
7440Sstevel@tonic-gate 
7450Sstevel@tonic-gate 			/*
7460Sstevel@tonic-gate 			 * Need the following check as it is possible to have
7470Sstevel@tonic-gate 			 * a provider that implements just random_ops and has
7480Sstevel@tonic-gate 			 * pi_mechanisms == NULL.
7490Sstevel@tonic-gate 			 */
7500Sstevel@tonic-gate 			if (info->pi_mechanisms != NULL) {
7510Sstevel@tonic-gate 				bcopy(info->pi_mechanisms, desc->pd_mechanisms,
7520Sstevel@tonic-gate 				    sizeof (crypto_mech_info_t) * (mcount - 1));
7530Sstevel@tonic-gate 			}
7540Sstevel@tonic-gate 			rand_mi = &desc->pd_mechanisms[mcount - 1];
7550Sstevel@tonic-gate 
7560Sstevel@tonic-gate 			bzero(rand_mi, sizeof (crypto_mech_info_t));
7570Sstevel@tonic-gate 			(void) strncpy(rand_mi->cm_mech_name, SUN_RANDOM,
7580Sstevel@tonic-gate 			    CRYPTO_MAX_MECH_NAME);
7590Sstevel@tonic-gate 			rand_mi->cm_func_group_mask = CRYPTO_FG_RANDOM;
7600Sstevel@tonic-gate 		} else {
7610Sstevel@tonic-gate 			ASSERT(info->pi_mechanisms != NULL);
7620Sstevel@tonic-gate 			bcopy(info->pi_mechanisms, desc->pd_mechanisms,
7630Sstevel@tonic-gate 			    sizeof (crypto_mech_info_t) * mcount);
7640Sstevel@tonic-gate 		}
7650Sstevel@tonic-gate 	}
7660Sstevel@tonic-gate 
7670Sstevel@tonic-gate 	/*
7680Sstevel@tonic-gate 	 * For each mechanism support by the provider, add the provider
7690Sstevel@tonic-gate 	 * to the corresponding KCF mechanism mech_entry chain.
7700Sstevel@tonic-gate 	 */
7710Sstevel@tonic-gate 	for (mech_idx = 0; mech_idx < desc->pd_mech_list_count; mech_idx++) {
7720Sstevel@tonic-gate 		crypto_mech_info_t *mi = &desc->pd_mechanisms[mech_idx];
7730Sstevel@tonic-gate 
7743708Skrishna 		if ((mi->cm_mech_flags & CRYPTO_KEYSIZE_UNIT_IN_BITS) &&
7753708Skrishna 		    (mi->cm_mech_flags & CRYPTO_KEYSIZE_UNIT_IN_BYTES)) {
7760Sstevel@tonic-gate 			err = CRYPTO_ARGUMENTS_BAD;
7770Sstevel@tonic-gate 			break;
7780Sstevel@tonic-gate 		}
7790Sstevel@tonic-gate 
7808384SBhargava.Yenduri@Sun.COM 		if ((err = kcf_add_mech_provider(mech_idx, desc, &pmd)) !=
7818384SBhargava.Yenduri@Sun.COM 		    KCF_SUCCESS)
7820Sstevel@tonic-gate 			break;
7830Sstevel@tonic-gate 
7840Sstevel@tonic-gate 		if (pmd == NULL)
7850Sstevel@tonic-gate 			continue;
7860Sstevel@tonic-gate 
7870Sstevel@tonic-gate 		/* The provider will be used for this mechanism */
7880Sstevel@tonic-gate 		desc_use_count++;
7890Sstevel@tonic-gate 	}
7900Sstevel@tonic-gate 
7910Sstevel@tonic-gate 	/*
7922817Smcpowers 	 * Don't allow multiple software providers with disabled mechanisms
7932817Smcpowers 	 * to register. Subsequent enabling of mechanisms will result in
7942817Smcpowers 	 * an unsupported configuration, i.e. multiple software providers
7952817Smcpowers 	 * per mechanism.
7960Sstevel@tonic-gate 	 */
7972817Smcpowers 	if (desc_use_count == 0 && desc->pd_prov_type == CRYPTO_SW_PROVIDER)
7980Sstevel@tonic-gate 		return (CRYPTO_ARGUMENTS_BAD);
7990Sstevel@tonic-gate 
8000Sstevel@tonic-gate 	if (err == KCF_SUCCESS)
8010Sstevel@tonic-gate 		return (CRYPTO_SUCCESS);
8020Sstevel@tonic-gate 
8030Sstevel@tonic-gate 	/*
8040Sstevel@tonic-gate 	 * An error occurred while adding the mechanism, cleanup
8050Sstevel@tonic-gate 	 * and bail.
8060Sstevel@tonic-gate 	 */
8070Sstevel@tonic-gate 	for (cleanup_idx = 0; cleanup_idx < mech_idx; cleanup_idx++) {
8080Sstevel@tonic-gate 		kcf_remove_mech_provider(
8090Sstevel@tonic-gate 		    desc->pd_mechanisms[cleanup_idx].cm_mech_name, desc);
8100Sstevel@tonic-gate 	}
8110Sstevel@tonic-gate 
8120Sstevel@tonic-gate 	if (err == KCF_MECH_TAB_FULL)
8130Sstevel@tonic-gate 		return (CRYPTO_HOST_MEMORY);
8140Sstevel@tonic-gate 
8150Sstevel@tonic-gate 	return (CRYPTO_ARGUMENTS_BAD);
8160Sstevel@tonic-gate }
8170Sstevel@tonic-gate 
8180Sstevel@tonic-gate /*
8190Sstevel@tonic-gate  * Update routine for kstat. Only privileged users are allowed to
8200Sstevel@tonic-gate  * access this information, since this information is sensitive.
8210Sstevel@tonic-gate  * There are some cryptographic attacks (e.g. traffic analysis)
8220Sstevel@tonic-gate  * which can use this information.
8230Sstevel@tonic-gate  */
8240Sstevel@tonic-gate static int
8250Sstevel@tonic-gate kcf_prov_kstat_update(kstat_t *ksp, int rw)
8260Sstevel@tonic-gate {
8270Sstevel@tonic-gate 	kcf_prov_stats_t *ks_data;
8280Sstevel@tonic-gate 	kcf_provider_desc_t *pd = (kcf_provider_desc_t *)ksp->ks_private;
8299505SBhargava.Yenduri@Sun.COM 	int i;
8300Sstevel@tonic-gate 
8310Sstevel@tonic-gate 	if (rw == KSTAT_WRITE)
8320Sstevel@tonic-gate 		return (EACCES);
8330Sstevel@tonic-gate 
8340Sstevel@tonic-gate 	ks_data = ksp->ks_data;
8350Sstevel@tonic-gate 
8360Sstevel@tonic-gate 	if (secpolicy_sys_config(CRED(), B_TRUE) != 0) {
8370Sstevel@tonic-gate 		ks_data->ps_ops_total.value.ui64 = 0;
8380Sstevel@tonic-gate 		ks_data->ps_ops_passed.value.ui64 = 0;
8390Sstevel@tonic-gate 		ks_data->ps_ops_failed.value.ui64 = 0;
8400Sstevel@tonic-gate 		ks_data->ps_ops_busy_rval.value.ui64 = 0;
8410Sstevel@tonic-gate 	} else {
8429505SBhargava.Yenduri@Sun.COM 		uint64_t dtotal, ftotal, btotal;
8439505SBhargava.Yenduri@Sun.COM 
8449505SBhargava.Yenduri@Sun.COM 		dtotal = ftotal = btotal = 0;
8459505SBhargava.Yenduri@Sun.COM 		/* No locking done since an exact count is not required. */
8469505SBhargava.Yenduri@Sun.COM 		for (i = 0; i < pd->pd_nbins; i++) {
8479505SBhargava.Yenduri@Sun.COM 			dtotal += pd->pd_percpu_bins[i].kp_ndispatches;
8489505SBhargava.Yenduri@Sun.COM 			ftotal += pd->pd_percpu_bins[i].kp_nfails;
8499505SBhargava.Yenduri@Sun.COM 			btotal += pd->pd_percpu_bins[i].kp_nbusy_rval;
8509505SBhargava.Yenduri@Sun.COM 		}
8519505SBhargava.Yenduri@Sun.COM 
8529505SBhargava.Yenduri@Sun.COM 		ks_data->ps_ops_total.value.ui64 = dtotal;
8539505SBhargava.Yenduri@Sun.COM 		ks_data->ps_ops_failed.value.ui64 = ftotal;
8549505SBhargava.Yenduri@Sun.COM 		ks_data->ps_ops_busy_rval.value.ui64 = btotal;
8559505SBhargava.Yenduri@Sun.COM 		ks_data->ps_ops_passed.value.ui64 = dtotal - ftotal - btotal;
8560Sstevel@tonic-gate 	}
8570Sstevel@tonic-gate 
8580Sstevel@tonic-gate 	return (0);
8590Sstevel@tonic-gate }
8600Sstevel@tonic-gate 
8610Sstevel@tonic-gate 
8620Sstevel@tonic-gate /*
8630Sstevel@tonic-gate  * Utility routine called from failure paths in crypto_register_provider()
8640Sstevel@tonic-gate  * and from crypto_load_soft_disabled().
8650Sstevel@tonic-gate  */
8660Sstevel@tonic-gate void
8670Sstevel@tonic-gate undo_register_provider(kcf_provider_desc_t *desc, boolean_t remove_prov)
8680Sstevel@tonic-gate {
8690Sstevel@tonic-gate 	uint_t mech_idx;
8700Sstevel@tonic-gate 
8710Sstevel@tonic-gate 	/* remove the provider from the mechanisms tables */
8720Sstevel@tonic-gate 	for (mech_idx = 0; mech_idx < desc->pd_mech_list_count;
8730Sstevel@tonic-gate 	    mech_idx++) {
8740Sstevel@tonic-gate 		kcf_remove_mech_provider(
8750Sstevel@tonic-gate 		    desc->pd_mechanisms[mech_idx].cm_mech_name, desc);
8760Sstevel@tonic-gate 	}
8770Sstevel@tonic-gate 
8780Sstevel@tonic-gate 	/* remove provider from providers table */
8790Sstevel@tonic-gate 	if (remove_prov)
8800Sstevel@tonic-gate 		(void) kcf_prov_tab_rem_provider(desc->pd_prov_id);
8810Sstevel@tonic-gate }
8820Sstevel@tonic-gate 
8834373Skrishna static void
8844373Skrishna undo_register_provider_extra(kcf_provider_desc_t *desc)
8854373Skrishna {
8864373Skrishna 	delete_kstat(desc);
8874373Skrishna 	undo_register_provider(desc, B_TRUE);
8884373Skrishna }
8894373Skrishna 
8900Sstevel@tonic-gate /*
8910Sstevel@tonic-gate  * Utility routine called from crypto_load_soft_disabled(). Callers
8920Sstevel@tonic-gate  * should have done a prior undo_register_provider().
8930Sstevel@tonic-gate  */
8940Sstevel@tonic-gate void
8950Sstevel@tonic-gate redo_register_provider(kcf_provider_desc_t *pd)
8960Sstevel@tonic-gate {
8970Sstevel@tonic-gate 	/* process the mechanisms supported by the provider */
8980Sstevel@tonic-gate 	(void) init_prov_mechs(NULL, pd);
8990Sstevel@tonic-gate 
9000Sstevel@tonic-gate 	/*
9010Sstevel@tonic-gate 	 * Hold provider in providers table. We should not call
9020Sstevel@tonic-gate 	 * kcf_prov_tab_add_provider() here as the provider descriptor
9030Sstevel@tonic-gate 	 * is still valid which means it has an entry in the provider
9040Sstevel@tonic-gate 	 * table.
9050Sstevel@tonic-gate 	 */
9060Sstevel@tonic-gate 	KCF_PROV_REFHOLD(pd);
9070Sstevel@tonic-gate }
9080Sstevel@tonic-gate 
9090Sstevel@tonic-gate /*
9100Sstevel@tonic-gate  * Add provider (p1) to another provider's array of providers (p2).
9110Sstevel@tonic-gate  * Hardware and logical providers use this array to cross-reference
9120Sstevel@tonic-gate  * each other.
9130Sstevel@tonic-gate  */
9140Sstevel@tonic-gate static void
9150Sstevel@tonic-gate add_provider_to_array(kcf_provider_desc_t *p1, kcf_provider_desc_t *p2)
9160Sstevel@tonic-gate {
9170Sstevel@tonic-gate 	kcf_provider_list_t *new;
9180Sstevel@tonic-gate 
9190Sstevel@tonic-gate 	new = kmem_alloc(sizeof (kcf_provider_list_t), KM_SLEEP);
9200Sstevel@tonic-gate 	mutex_enter(&p2->pd_lock);
9210Sstevel@tonic-gate 	new->pl_next = p2->pd_provider_list;
9220Sstevel@tonic-gate 	p2->pd_provider_list = new;
9230Sstevel@tonic-gate 	new->pl_provider = p1;
9240Sstevel@tonic-gate 	mutex_exit(&p2->pd_lock);
9250Sstevel@tonic-gate }
9260Sstevel@tonic-gate 
9270Sstevel@tonic-gate /*
9280Sstevel@tonic-gate  * Remove provider (p1) from another provider's array of providers (p2).
9290Sstevel@tonic-gate  * Hardware and logical providers use this array to cross-reference
9300Sstevel@tonic-gate  * each other.
9310Sstevel@tonic-gate  */
9320Sstevel@tonic-gate static void
9330Sstevel@tonic-gate remove_provider_from_array(kcf_provider_desc_t *p1, kcf_provider_desc_t *p2)
9340Sstevel@tonic-gate {
9350Sstevel@tonic-gate 
9360Sstevel@tonic-gate 	kcf_provider_list_t *pl = NULL, **prev;
9370Sstevel@tonic-gate 
9380Sstevel@tonic-gate 	mutex_enter(&p2->pd_lock);
9390Sstevel@tonic-gate 	for (pl = p2->pd_provider_list, prev = &p2->pd_provider_list;
9400Sstevel@tonic-gate 	    pl != NULL; prev = &pl->pl_next, pl = pl->pl_next) {
9410Sstevel@tonic-gate 		if (pl->pl_provider == p1) {
9420Sstevel@tonic-gate 			break;
9430Sstevel@tonic-gate 		}
9440Sstevel@tonic-gate 	}
9450Sstevel@tonic-gate 
9460Sstevel@tonic-gate 	if (p1 == NULL) {
9470Sstevel@tonic-gate 		mutex_exit(&p2->pd_lock);
9480Sstevel@tonic-gate 		return;
9490Sstevel@tonic-gate 	}
9500Sstevel@tonic-gate 
9510Sstevel@tonic-gate 	/* detach and free kcf_provider_list structure */
9520Sstevel@tonic-gate 	*prev = pl->pl_next;
9530Sstevel@tonic-gate 	kmem_free(pl, sizeof (*pl));
9540Sstevel@tonic-gate 	mutex_exit(&p2->pd_lock);
9550Sstevel@tonic-gate }
9560Sstevel@tonic-gate 
9570Sstevel@tonic-gate /*
9580Sstevel@tonic-gate  * Convert an array of logical provider handles (crypto_provider_id)
9590Sstevel@tonic-gate  * stored in a crypto_provider_info structure into an array of provider
9600Sstevel@tonic-gate  * descriptors (kcf_provider_desc_t) attached to a logical provider.
9610Sstevel@tonic-gate  */
9620Sstevel@tonic-gate static void
9630Sstevel@tonic-gate process_logical_providers(crypto_provider_info_t *info, kcf_provider_desc_t *hp)
9640Sstevel@tonic-gate {
9650Sstevel@tonic-gate 	kcf_provider_desc_t *lp;
9660Sstevel@tonic-gate 	crypto_provider_id_t handle;
9670Sstevel@tonic-gate 	int count = info->pi_logical_provider_count;
9680Sstevel@tonic-gate 	int i;
9690Sstevel@tonic-gate 
9700Sstevel@tonic-gate 	/* add hardware provider to each logical provider */
9710Sstevel@tonic-gate 	for (i = 0; i < count; i++) {
9720Sstevel@tonic-gate 		handle = info->pi_logical_providers[i];
9730Sstevel@tonic-gate 		lp = kcf_prov_tab_lookup((crypto_provider_id_t)handle);
9740Sstevel@tonic-gate 		if (lp == NULL) {
9750Sstevel@tonic-gate 			continue;
9760Sstevel@tonic-gate 		}
9770Sstevel@tonic-gate 		add_provider_to_array(hp, lp);
9782800Skrishna 		hp->pd_flags |= KCF_LPROV_MEMBER;
9790Sstevel@tonic-gate 
9800Sstevel@tonic-gate 		/*
9810Sstevel@tonic-gate 		 * A hardware provider has to have the provider descriptor of
9820Sstevel@tonic-gate 		 * every logical provider it belongs to, so it can be removed
9830Sstevel@tonic-gate 		 * from the logical provider if the hardware provider
9840Sstevel@tonic-gate 		 * unregisters from the framework.
9850Sstevel@tonic-gate 		 */
9860Sstevel@tonic-gate 		add_provider_to_array(lp, hp);
9870Sstevel@tonic-gate 		KCF_PROV_REFRELE(lp);
9880Sstevel@tonic-gate 	}
9890Sstevel@tonic-gate }
9900Sstevel@tonic-gate 
9910Sstevel@tonic-gate /*
9920Sstevel@tonic-gate  * This routine removes a provider from all of the logical or
9930Sstevel@tonic-gate  * hardware providers it belongs to, and frees the provider's
9940Sstevel@tonic-gate  * array of pointers to providers.
9950Sstevel@tonic-gate  */
9960Sstevel@tonic-gate static void
9970Sstevel@tonic-gate remove_provider(kcf_provider_desc_t *pp)
9980Sstevel@tonic-gate {
9990Sstevel@tonic-gate 	kcf_provider_desc_t *p;
10000Sstevel@tonic-gate 	kcf_provider_list_t *e, *next;
10010Sstevel@tonic-gate 
10020Sstevel@tonic-gate 	mutex_enter(&pp->pd_lock);
10030Sstevel@tonic-gate 	for (e = pp->pd_provider_list; e != NULL; e = next) {
10040Sstevel@tonic-gate 		p = e->pl_provider;
10050Sstevel@tonic-gate 		remove_provider_from_array(pp, p);
10062800Skrishna 		if (p->pd_prov_type == CRYPTO_HW_PROVIDER &&
10072800Skrishna 		    p->pd_provider_list == NULL)
10082800Skrishna 			p->pd_flags &= ~KCF_LPROV_MEMBER;
10090Sstevel@tonic-gate 		next = e->pl_next;
10100Sstevel@tonic-gate 		kmem_free(e, sizeof (*e));
10110Sstevel@tonic-gate 	}
10120Sstevel@tonic-gate 	pp->pd_provider_list = NULL;
10130Sstevel@tonic-gate 	mutex_exit(&pp->pd_lock);
10140Sstevel@tonic-gate }
10154373Skrishna 
10164373Skrishna /*
10174373Skrishna  * Dispatch events as needed for a provider. is_added flag tells
10184373Skrishna  * whether the provider is registering or unregistering.
10194373Skrishna  */
10204373Skrishna void
10214373Skrishna kcf_do_notify(kcf_provider_desc_t *prov_desc, boolean_t is_added)
10224373Skrishna {
10234373Skrishna 	int i;
10244373Skrishna 	crypto_notify_event_change_t ec;
10254373Skrishna 
10264373Skrishna 	ASSERT(prov_desc->pd_state > KCF_PROV_VERIFICATION_FAILED);
10274373Skrishna 
10284373Skrishna 	/*
10294373Skrishna 	 * Inform interested clients of the mechanisms becoming
10304373Skrishna 	 * available/unavailable. We skip this for logical providers
10314373Skrishna 	 * as they do not affect mechanisms.
10324373Skrishna 	 */
10334373Skrishna 	if (prov_desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) {
10344373Skrishna 		ec.ec_provider_type = prov_desc->pd_prov_type;
10354373Skrishna 		ec.ec_change = is_added ? CRYPTO_MECH_ADDED :
10364373Skrishna 		    CRYPTO_MECH_REMOVED;
10374373Skrishna 		for (i = 0; i < prov_desc->pd_mech_list_count; i++) {
10384373Skrishna 			/* Skip any mechanisms not allowed by the policy */
10394373Skrishna 			if (is_mech_disabled(prov_desc,
10404373Skrishna 			    prov_desc->pd_mechanisms[i].cm_mech_name))
10414373Skrishna 				continue;
10424373Skrishna 
10434373Skrishna 			(void) strncpy(ec.ec_mech_name,
10444373Skrishna 			    prov_desc->pd_mechanisms[i].cm_mech_name,
10454373Skrishna 			    CRYPTO_MAX_MECH_NAME);
10464373Skrishna 			kcf_walk_ntfylist(CRYPTO_EVENT_MECHS_CHANGED, &ec);
10474373Skrishna 		}
10484373Skrishna 
10494373Skrishna 	}
10504373Skrishna 
10514373Skrishna 	/*
10524373Skrishna 	 * Inform interested clients about the new or departing provider.
10534373Skrishna 	 * In case of a logical provider, we need to notify the event only
10544373Skrishna 	 * for the logical provider and not for the underlying
10554373Skrishna 	 * providers which are known by the KCF_LPROV_MEMBER bit.
10564373Skrishna 	 */
10574373Skrishna 	if (prov_desc->pd_prov_type == CRYPTO_LOGICAL_PROVIDER ||
10584373Skrishna 	    (prov_desc->pd_flags & KCF_LPROV_MEMBER) == 0) {
10594373Skrishna 		kcf_walk_ntfylist(is_added ? CRYPTO_EVENT_PROVIDER_REGISTERED :
10604373Skrishna 		    CRYPTO_EVENT_PROVIDER_UNREGISTERED, prov_desc);
10614373Skrishna 	}
10624373Skrishna }
10634373Skrishna 
10644373Skrishna static void
10654373Skrishna delete_kstat(kcf_provider_desc_t *desc)
10664373Skrishna {
10674373Skrishna 	/* destroy the kstat created for this provider */
10684373Skrishna 	if (desc->pd_kstat != NULL) {
10694373Skrishna 		kcf_provider_desc_t *kspd = desc->pd_kstat->ks_private;
10704373Skrishna 
10714373Skrishna 		/* release reference held by desc->pd_kstat->ks_private */
10724373Skrishna 		ASSERT(desc == kspd);
10734373Skrishna 		kstat_delete(kspd->pd_kstat);
10744373Skrishna 		desc->pd_kstat = NULL;
10754373Skrishna 		KCF_PROV_REFRELE(kspd);
10764373Skrishna 	}
10774373Skrishna }
1078