xref: /titanic_52/usr/src/uts/common/crypto/spi/kcf_spi.c (revision 6ea3c0609e50782557505b88bb391b786bca32c9)
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
5c892ebf1Skrishna  * Common Development and Distribution License (the "License").
6c892ebf1Skrishna  * 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 /*
22d3b2efc7SAnthony Scarpino  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
25*6ea3c060SGarrett D'Amore /*
26*6ea3c060SGarrett D'Amore  * Copyright 2010 Nexenta Systems, Inc.  All rights reserved.
27*6ea3c060SGarrett D'Amore  */
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate /*
307c478bd9Sstevel@tonic-gate  * This file is part of the core Kernel Cryptographic Framework.
317c478bd9Sstevel@tonic-gate  * It implements the SPI functions exported to cryptographic
327c478bd9Sstevel@tonic-gate  * providers.
337c478bd9Sstevel@tonic-gate  */
347c478bd9Sstevel@tonic-gate 
357c478bd9Sstevel@tonic-gate #include <sys/ksynch.h>
367c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
377c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
387c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
397c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
407c478bd9Sstevel@tonic-gate #include <sys/crypto/common.h>
417c478bd9Sstevel@tonic-gate #include <sys/crypto/impl.h>
427c478bd9Sstevel@tonic-gate #include <sys/crypto/sched_impl.h>
437c478bd9Sstevel@tonic-gate #include <sys/crypto/spi.h>
4473556491SAnthony Scarpino #include <sys/crypto/ioctladmin.h>
457c478bd9Sstevel@tonic-gate #include <sys/taskq.h>
467c478bd9Sstevel@tonic-gate #include <sys/disp.h>
477c478bd9Sstevel@tonic-gate #include <sys/kstat.h>
487c478bd9Sstevel@tonic-gate #include <sys/policy.h>
49c41e7ccaSkrishna #include <sys/cpuvar.h>
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate /*
527c478bd9Sstevel@tonic-gate  * minalloc and maxalloc values to be used for taskq_create().
537c478bd9Sstevel@tonic-gate  */
54c41e7ccaSkrishna int crypto_taskq_threads = CRYPTO_TASKQ_THREADS;
557c478bd9Sstevel@tonic-gate int crypto_taskq_minalloc = CYRPTO_TASKQ_MIN;
567c478bd9Sstevel@tonic-gate int crypto_taskq_maxalloc = CRYPTO_TASKQ_MAX;
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate static void remove_provider(kcf_provider_desc_t *);
597c478bd9Sstevel@tonic-gate static void process_logical_providers(crypto_provider_info_t *,
607c478bd9Sstevel@tonic-gate     kcf_provider_desc_t *);
617c478bd9Sstevel@tonic-gate static int init_prov_mechs(crypto_provider_info_t *, kcf_provider_desc_t *);
627c478bd9Sstevel@tonic-gate static int kcf_prov_kstat_update(kstat_t *, int);
63fe2f7468Skrishna static void delete_kstat(kcf_provider_desc_t *);
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate static kcf_prov_stats_t kcf_stats_ks_data_template = {
667c478bd9Sstevel@tonic-gate 	{ "kcf_ops_total",		KSTAT_DATA_UINT64 },
677c478bd9Sstevel@tonic-gate 	{ "kcf_ops_passed",		KSTAT_DATA_UINT64 },
687c478bd9Sstevel@tonic-gate 	{ "kcf_ops_failed",		KSTAT_DATA_UINT64 },
697c478bd9Sstevel@tonic-gate 	{ "kcf_ops_returned_busy",	KSTAT_DATA_UINT64 }
707c478bd9Sstevel@tonic-gate };
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate #define	KCF_SPI_COPY_OPS(src, dst, ops) if ((src)->ops != NULL) \
737c478bd9Sstevel@tonic-gate 	*((dst)->ops) = *((src)->ops);
747c478bd9Sstevel@tonic-gate 
75d3b2efc7SAnthony Scarpino extern int sys_shutdown;
76d3b2efc7SAnthony Scarpino 
777c478bd9Sstevel@tonic-gate /*
78034448feSmcpowers  * Copy an ops vector from src to dst. Used during provider registration
79034448feSmcpowers  * to copy the ops vector from the provider info structure to the
80034448feSmcpowers  * provider descriptor maintained by KCF.
81034448feSmcpowers  * Copying the ops vector specified by the provider is needed since the
82034448feSmcpowers  * framework does not require the provider info structure to be
83034448feSmcpowers  * persistent.
84034448feSmcpowers  */
85034448feSmcpowers static void
86034448feSmcpowers copy_ops_vector_v1(crypto_ops_t *src_ops, crypto_ops_t *dst_ops)
87034448feSmcpowers {
88034448feSmcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_control_ops);
89034448feSmcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_digest_ops);
90034448feSmcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_cipher_ops);
91034448feSmcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_mac_ops);
92034448feSmcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_sign_ops);
93034448feSmcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_verify_ops);
94034448feSmcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_dual_ops);
95034448feSmcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_dual_cipher_mac_ops);
96034448feSmcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_random_ops);
97034448feSmcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_session_ops);
98034448feSmcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_object_ops);
99034448feSmcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_key_ops);
100034448feSmcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_provider_ops);
101034448feSmcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_ctx_ops);
102034448feSmcpowers }
103034448feSmcpowers 
104034448feSmcpowers static void
105034448feSmcpowers copy_ops_vector_v2(crypto_ops_t *src_ops, crypto_ops_t *dst_ops)
106034448feSmcpowers {
107034448feSmcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_mech_ops);
108034448feSmcpowers }
109034448feSmcpowers 
110034448feSmcpowers static void
111034448feSmcpowers copy_ops_vector_v3(crypto_ops_t *src_ops, crypto_ops_t *dst_ops)
112034448feSmcpowers {
113034448feSmcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_nostore_key_ops);
114034448feSmcpowers }
115034448feSmcpowers 
11673556491SAnthony Scarpino static void
11773556491SAnthony Scarpino copy_ops_vector_v4(crypto_ops_t *src_ops, crypto_ops_t *dst_ops)
11873556491SAnthony Scarpino {
11973556491SAnthony Scarpino 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_fips140_ops);
12073556491SAnthony Scarpino }
12173556491SAnthony Scarpino 
122034448feSmcpowers /*
1237c478bd9Sstevel@tonic-gate  * This routine is used to add cryptographic providers to the KEF framework.
1247c478bd9Sstevel@tonic-gate  * Providers pass a crypto_provider_info structure to crypto_register_provider()
1257c478bd9Sstevel@tonic-gate  * and get back a handle.  The crypto_provider_info structure contains a
1267c478bd9Sstevel@tonic-gate  * list of mechanisms supported by the provider and an ops vector containing
1277c478bd9Sstevel@tonic-gate  * provider entry points.  Hardware providers call this routine in their attach
1287c478bd9Sstevel@tonic-gate  * routines.  Software providers call this routine in their _init() routine.
1297c478bd9Sstevel@tonic-gate  */
1307c478bd9Sstevel@tonic-gate int
1317c478bd9Sstevel@tonic-gate crypto_register_provider(crypto_provider_info_t *info,
1327c478bd9Sstevel@tonic-gate     crypto_kcf_provider_handle_t *handle)
1337c478bd9Sstevel@tonic-gate {
1347c478bd9Sstevel@tonic-gate 	struct modctl *mcp;
1357c478bd9Sstevel@tonic-gate 	char *name;
1367c478bd9Sstevel@tonic-gate 	char ks_name[KSTAT_STRLEN];
1377c478bd9Sstevel@tonic-gate 	kcf_provider_desc_t *prov_desc = NULL;
1387c478bd9Sstevel@tonic-gate 	int ret = CRYPTO_ARGUMENTS_BAD;
1397c478bd9Sstevel@tonic-gate 
140d3b2efc7SAnthony Scarpino 	if (info->pi_interface_version > CRYPTO_SPI_VERSION_4) {
141d3b2efc7SAnthony Scarpino 		ret = CRYPTO_VERSION_MISMATCH;
142d3b2efc7SAnthony Scarpino 		goto errormsg;
143d3b2efc7SAnthony Scarpino 	}
1447c478bd9Sstevel@tonic-gate 
1457c478bd9Sstevel@tonic-gate 	/*
1467c478bd9Sstevel@tonic-gate 	 * Check provider type, must be software, hardware, or logical.
1477c478bd9Sstevel@tonic-gate 	 */
1487c478bd9Sstevel@tonic-gate 	if (info->pi_provider_type != CRYPTO_HW_PROVIDER &&
1497c478bd9Sstevel@tonic-gate 	    info->pi_provider_type != CRYPTO_SW_PROVIDER &&
1507c478bd9Sstevel@tonic-gate 	    info->pi_provider_type != CRYPTO_LOGICAL_PROVIDER)
151d3b2efc7SAnthony Scarpino 		goto errormsg;
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate 	/*
1547c478bd9Sstevel@tonic-gate 	 * Allocate and initialize a new provider descriptor. We also
1557c478bd9Sstevel@tonic-gate 	 * hold it and release it when done.
1567c478bd9Sstevel@tonic-gate 	 */
1577c478bd9Sstevel@tonic-gate 	prov_desc = kcf_alloc_provider_desc(info);
1587c478bd9Sstevel@tonic-gate 	KCF_PROV_REFHOLD(prov_desc);
1597c478bd9Sstevel@tonic-gate 
1607c478bd9Sstevel@tonic-gate 	prov_desc->pd_prov_type = info->pi_provider_type;
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate 	/* provider-private handle, opaque to KCF */
1637c478bd9Sstevel@tonic-gate 	prov_desc->pd_prov_handle = info->pi_provider_handle;
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 	/* copy provider description string */
1667c478bd9Sstevel@tonic-gate 	if (info->pi_provider_description != NULL) {
1677c478bd9Sstevel@tonic-gate 		/*
1687c478bd9Sstevel@tonic-gate 		 * pi_provider_descriptor is a string that can contain
1697c478bd9Sstevel@tonic-gate 		 * up to CRYPTO_PROVIDER_DESCR_MAX_LEN + 1 characters
1707c478bd9Sstevel@tonic-gate 		 * INCLUDING the terminating null character. A bcopy()
1717c478bd9Sstevel@tonic-gate 		 * is necessary here as pd_description should not have
1727c478bd9Sstevel@tonic-gate 		 * a null character. See comments in kcf_alloc_provider_desc()
1737c478bd9Sstevel@tonic-gate 		 * for details on pd_description field.
1747c478bd9Sstevel@tonic-gate 		 */
1757c478bd9Sstevel@tonic-gate 		bcopy(info->pi_provider_description, prov_desc->pd_description,
1767c478bd9Sstevel@tonic-gate 		    min(strlen(info->pi_provider_description),
1777c478bd9Sstevel@tonic-gate 		    CRYPTO_PROVIDER_DESCR_MAX_LEN));
1787c478bd9Sstevel@tonic-gate 	}
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 	if (info->pi_provider_type != CRYPTO_LOGICAL_PROVIDER) {
1817c478bd9Sstevel@tonic-gate 		if (info->pi_ops_vector == NULL) {
182034448feSmcpowers 			goto bail;
1837c478bd9Sstevel@tonic-gate 		}
184894b2776Smcpowers 		copy_ops_vector_v1(info->pi_ops_vector,
185894b2776Smcpowers 		    prov_desc->pd_ops_vector);
186034448feSmcpowers 		if (info->pi_interface_version >= CRYPTO_SPI_VERSION_2) {
187894b2776Smcpowers 			copy_ops_vector_v2(info->pi_ops_vector,
188894b2776Smcpowers 			    prov_desc->pd_ops_vector);
189894b2776Smcpowers 			prov_desc->pd_flags = info->pi_flags;
190894b2776Smcpowers 		}
19173556491SAnthony Scarpino 		if (info->pi_interface_version >= CRYPTO_SPI_VERSION_3) {
192034448feSmcpowers 			copy_ops_vector_v3(info->pi_ops_vector,
193034448feSmcpowers 			    prov_desc->pd_ops_vector);
194034448feSmcpowers 		}
19573556491SAnthony Scarpino 		if (info->pi_interface_version == CRYPTO_SPI_VERSION_4) {
19673556491SAnthony Scarpino 			copy_ops_vector_v4(info->pi_ops_vector,
19773556491SAnthony Scarpino 			    prov_desc->pd_ops_vector);
19873556491SAnthony Scarpino 		}
1997c478bd9Sstevel@tonic-gate 	}
2007c478bd9Sstevel@tonic-gate 
201034448feSmcpowers 	/* object_ops and nostore_key_ops are mutually exclusive */
202034448feSmcpowers 	if (prov_desc->pd_ops_vector->co_object_ops &&
203034448feSmcpowers 	    prov_desc->pd_ops_vector->co_nostore_key_ops) {
204034448feSmcpowers 		goto bail;
205034448feSmcpowers 	}
2067c478bd9Sstevel@tonic-gate 	/*
2077c478bd9Sstevel@tonic-gate 	 * For software providers, copy the module name and module ID.
2087c478bd9Sstevel@tonic-gate 	 * For hardware providers, copy the driver name and instance.
2097c478bd9Sstevel@tonic-gate 	 */
2107c478bd9Sstevel@tonic-gate 	switch (info->pi_provider_type) {
2117c478bd9Sstevel@tonic-gate 	case  CRYPTO_SW_PROVIDER:
2127c478bd9Sstevel@tonic-gate 		if (info->pi_provider_dev.pd_sw == NULL)
2137c478bd9Sstevel@tonic-gate 			goto bail;
2147c478bd9Sstevel@tonic-gate 
2157c478bd9Sstevel@tonic-gate 		if ((mcp = mod_getctl(info->pi_provider_dev.pd_sw)) == NULL)
2167c478bd9Sstevel@tonic-gate 			goto bail;
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate 		prov_desc->pd_module_id = mcp->mod_id;
2197c478bd9Sstevel@tonic-gate 		name = mcp->mod_modname;
2207c478bd9Sstevel@tonic-gate 		break;
2217c478bd9Sstevel@tonic-gate 
2227c478bd9Sstevel@tonic-gate 	case CRYPTO_HW_PROVIDER:
2237c478bd9Sstevel@tonic-gate 	case CRYPTO_LOGICAL_PROVIDER:
2247c478bd9Sstevel@tonic-gate 		if (info->pi_provider_dev.pd_hw == NULL)
2257c478bd9Sstevel@tonic-gate 			goto bail;
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 		prov_desc->pd_instance =
2287c478bd9Sstevel@tonic-gate 		    ddi_get_instance(info->pi_provider_dev.pd_hw);
2297c478bd9Sstevel@tonic-gate 		name = (char *)ddi_driver_name(info->pi_provider_dev.pd_hw);
2307c478bd9Sstevel@tonic-gate 		break;
2317c478bd9Sstevel@tonic-gate 	}
2327c478bd9Sstevel@tonic-gate 	if (name == NULL)
2337c478bd9Sstevel@tonic-gate 		goto bail;
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate 	prov_desc->pd_name = kmem_alloc(strlen(name) + 1, KM_SLEEP);
2367c478bd9Sstevel@tonic-gate 	(void) strcpy(prov_desc->pd_name, name);
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate 	if ((prov_desc->pd_mctlp = kcf_get_modctl(info)) == NULL)
2397c478bd9Sstevel@tonic-gate 		goto bail;
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate 	/* process the mechanisms supported by the provider */
2427c478bd9Sstevel@tonic-gate 	if ((ret = init_prov_mechs(info, prov_desc)) != CRYPTO_SUCCESS)
2437c478bd9Sstevel@tonic-gate 		goto bail;
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate 	/*
2467c478bd9Sstevel@tonic-gate 	 * Add provider to providers tables, also sets the descriptor
2477c478bd9Sstevel@tonic-gate 	 * pd_prov_id field.
2487c478bd9Sstevel@tonic-gate 	 */
2497c478bd9Sstevel@tonic-gate 	if ((ret = kcf_prov_tab_add_provider(prov_desc)) != CRYPTO_SUCCESS) {
2507c478bd9Sstevel@tonic-gate 		undo_register_provider(prov_desc, B_FALSE);
2517c478bd9Sstevel@tonic-gate 		goto bail;
2527c478bd9Sstevel@tonic-gate 	}
2537c478bd9Sstevel@tonic-gate 
2547c478bd9Sstevel@tonic-gate 	/*
2557c478bd9Sstevel@tonic-gate 	 * We create a taskq only for a hardware provider. The global
256c41e7ccaSkrishna 	 * software queue is used for software providers. We handle ordering
257c41e7ccaSkrishna 	 * of multi-part requests in the taskq routine. So, it is safe to
258c41e7ccaSkrishna 	 * have multiple threads for the taskq. We pass TASKQ_PREPOPULATE flag
259c41e7ccaSkrishna 	 * to keep some entries cached to improve performance.
2607c478bd9Sstevel@tonic-gate 	 */
2617c478bd9Sstevel@tonic-gate 	if (prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER)
262ef56a3c5SKrishna Yenduri 		prov_desc->pd_taskq = taskq_create("kcf_taskq",
263c41e7ccaSkrishna 		    crypto_taskq_threads, minclsyspri,
264c41e7ccaSkrishna 		    crypto_taskq_minalloc, crypto_taskq_maxalloc,
265c41e7ccaSkrishna 		    TASKQ_PREPOPULATE);
2667c478bd9Sstevel@tonic-gate 	else
267ef56a3c5SKrishna Yenduri 		prov_desc->pd_taskq = NULL;
2687c478bd9Sstevel@tonic-gate 
2694df55fdeSJanie Lu 	/* no kernel session to logical providers and no pd_flags  */
2707c478bd9Sstevel@tonic-gate 	if (prov_desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) {
2717c478bd9Sstevel@tonic-gate 		/*
2727c478bd9Sstevel@tonic-gate 		 * Open a session for session-oriented providers. This session
2737c478bd9Sstevel@tonic-gate 		 * is used for all kernel consumers. This is fine as a provider
2747c478bd9Sstevel@tonic-gate 		 * is required to support multiple thread access to a session.
2757c478bd9Sstevel@tonic-gate 		 * We can do this only after the taskq has been created as we
2767c478bd9Sstevel@tonic-gate 		 * do a kcf_submit_request() to open the session.
2777c478bd9Sstevel@tonic-gate 		 */
2787c478bd9Sstevel@tonic-gate 		if (KCF_PROV_SESSION_OPS(prov_desc) != NULL) {
2797c478bd9Sstevel@tonic-gate 			kcf_req_params_t params;
2807c478bd9Sstevel@tonic-gate 
2817c478bd9Sstevel@tonic-gate 			KCF_WRAP_SESSION_OPS_PARAMS(&params,
2827c478bd9Sstevel@tonic-gate 			    KCF_OP_SESSION_OPEN, &prov_desc->pd_sid, 0,
2837c478bd9Sstevel@tonic-gate 			    CRYPTO_USER, NULL, 0, prov_desc);
2847c478bd9Sstevel@tonic-gate 			ret = kcf_submit_request(prov_desc, NULL, NULL, &params,
2857c478bd9Sstevel@tonic-gate 			    B_FALSE);
2864df55fdeSJanie Lu 			if (ret != CRYPTO_SUCCESS)
2874df55fdeSJanie Lu 				goto undo_then_bail;
2884df55fdeSJanie Lu 		}
2897c478bd9Sstevel@tonic-gate 
2904df55fdeSJanie Lu 		/*
2914df55fdeSJanie Lu 		 * Get the value for the maximum input length allowed if
2924df55fdeSJanie Lu 		 * CRYPTO_HASH_NO_UPDATE or CRYPTO_HASH_NO_UPDATE is specified.
2934df55fdeSJanie Lu 		 */
2944df55fdeSJanie Lu 		if (prov_desc->pd_flags &
2954df55fdeSJanie Lu 		    (CRYPTO_HASH_NO_UPDATE | CRYPTO_HMAC_NO_UPDATE)) {
2964df55fdeSJanie Lu 			kcf_req_params_t params;
2974df55fdeSJanie Lu 			crypto_provider_ext_info_t ext_info;
2984df55fdeSJanie Lu 
2994df55fdeSJanie Lu 			if (KCF_PROV_PROVMGMT_OPS(prov_desc) == NULL)
3004df55fdeSJanie Lu 				goto undo_then_bail;
3014df55fdeSJanie Lu 
3024df55fdeSJanie Lu 			bzero(&ext_info, sizeof (ext_info));
3034df55fdeSJanie Lu 			KCF_WRAP_PROVMGMT_OPS_PARAMS(&params,
3044df55fdeSJanie Lu 			    KCF_OP_MGMT_EXTINFO,
3054df55fdeSJanie Lu 			    0, NULL, 0, NULL, 0, NULL, &ext_info, prov_desc);
3064df55fdeSJanie Lu 			ret = kcf_submit_request(prov_desc, NULL, NULL,
3074df55fdeSJanie Lu 			    &params, B_FALSE);
3084df55fdeSJanie Lu 			if (ret != CRYPTO_SUCCESS)
3094df55fdeSJanie Lu 				goto undo_then_bail;
3104df55fdeSJanie Lu 
3114df55fdeSJanie Lu 			if (prov_desc->pd_flags & CRYPTO_HASH_NO_UPDATE) {
3124df55fdeSJanie Lu 				prov_desc->pd_hash_limit =
3134df55fdeSJanie Lu 				    ext_info.ei_hash_max_input_len;
3144df55fdeSJanie Lu 			}
3154df55fdeSJanie Lu 			if (prov_desc->pd_flags & CRYPTO_HMAC_NO_UPDATE) {
3164df55fdeSJanie Lu 				prov_desc->pd_hmac_limit =
3174df55fdeSJanie Lu 				    ext_info.ei_hmac_max_input_len;
3187c478bd9Sstevel@tonic-gate 			}
3197c478bd9Sstevel@tonic-gate 		}
3207c478bd9Sstevel@tonic-gate 	}
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 	if (prov_desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) {
3237c478bd9Sstevel@tonic-gate 		/*
3247c478bd9Sstevel@tonic-gate 		 * Create the kstat for this provider. There is a kstat
3257c478bd9Sstevel@tonic-gate 		 * installed for each successfully registered provider.
3267c478bd9Sstevel@tonic-gate 		 * This kstat is deleted, when the provider unregisters.
3277c478bd9Sstevel@tonic-gate 		 */
3287c478bd9Sstevel@tonic-gate 		if (prov_desc->pd_prov_type == CRYPTO_SW_PROVIDER) {
3297c478bd9Sstevel@tonic-gate 			(void) snprintf(ks_name, KSTAT_STRLEN, "%s_%s",
3307c478bd9Sstevel@tonic-gate 			    prov_desc->pd_name, "provider_stats");
3317c478bd9Sstevel@tonic-gate 		} else {
3327c478bd9Sstevel@tonic-gate 			(void) snprintf(ks_name, KSTAT_STRLEN, "%s_%d_%u_%s",
3337c478bd9Sstevel@tonic-gate 			    prov_desc->pd_name, prov_desc->pd_instance,
3347c478bd9Sstevel@tonic-gate 			    prov_desc->pd_prov_id, "provider_stats");
3357c478bd9Sstevel@tonic-gate 		}
3367c478bd9Sstevel@tonic-gate 
3377c478bd9Sstevel@tonic-gate 		prov_desc->pd_kstat = kstat_create("kcf", 0, ks_name, "crypto",
3387c478bd9Sstevel@tonic-gate 		    KSTAT_TYPE_NAMED, sizeof (kcf_prov_stats_t) /
3397c478bd9Sstevel@tonic-gate 		    sizeof (kstat_named_t), KSTAT_FLAG_VIRTUAL);
3407c478bd9Sstevel@tonic-gate 
3417c478bd9Sstevel@tonic-gate 		if (prov_desc->pd_kstat != NULL) {
3427c478bd9Sstevel@tonic-gate 			bcopy(&kcf_stats_ks_data_template,
3437c478bd9Sstevel@tonic-gate 			    &prov_desc->pd_ks_data,
3447c478bd9Sstevel@tonic-gate 			    sizeof (kcf_stats_ks_data_template));
3457c478bd9Sstevel@tonic-gate 			prov_desc->pd_kstat->ks_data = &prov_desc->pd_ks_data;
3467c478bd9Sstevel@tonic-gate 			KCF_PROV_REFHOLD(prov_desc);
3477c478bd9Sstevel@tonic-gate 			prov_desc->pd_kstat->ks_private = prov_desc;
3487c478bd9Sstevel@tonic-gate 			prov_desc->pd_kstat->ks_update = kcf_prov_kstat_update;
3497c478bd9Sstevel@tonic-gate 			kstat_install(prov_desc->pd_kstat);
3507c478bd9Sstevel@tonic-gate 		}
3517c478bd9Sstevel@tonic-gate 	}
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 	if (prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER)
3547c478bd9Sstevel@tonic-gate 		process_logical_providers(info, prov_desc);
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate 	mutex_enter(&prov_desc->pd_lock);
357fe2f7468Skrishna 	prov_desc->pd_state = KCF_PROV_READY;
3587c478bd9Sstevel@tonic-gate 	mutex_exit(&prov_desc->pd_lock);
359fe2f7468Skrishna 	kcf_do_notify(prov_desc, B_TRUE);
3607c478bd9Sstevel@tonic-gate 
36173556491SAnthony Scarpino exit:
3627c478bd9Sstevel@tonic-gate 	*handle = prov_desc->pd_kcf_prov_handle;
3634df55fdeSJanie Lu 	KCF_PROV_REFRELE(prov_desc);
3644df55fdeSJanie Lu 	return (CRYPTO_SUCCESS);
3657c478bd9Sstevel@tonic-gate 
3664df55fdeSJanie Lu undo_then_bail:
3674df55fdeSJanie Lu 	undo_register_provider(prov_desc, B_TRUE);
3684df55fdeSJanie Lu 	ret = CRYPTO_FAILED;
3697c478bd9Sstevel@tonic-gate bail:
3707c478bd9Sstevel@tonic-gate 	KCF_PROV_REFRELE(prov_desc);
371d3b2efc7SAnthony Scarpino 
372d3b2efc7SAnthony Scarpino errormsg:
373d3b2efc7SAnthony Scarpino 	if (ret != CRYPTO_SUCCESS && sys_shutdown == 0) {
374d3b2efc7SAnthony Scarpino 		switch (ret) {
375d3b2efc7SAnthony Scarpino 		case CRYPTO_FAILED:
376d3b2efc7SAnthony Scarpino 			cmn_err(CE_WARN, "%s failed when registering with the "
377d3b2efc7SAnthony Scarpino 			    "Cryptographic Framework.",
378d3b2efc7SAnthony Scarpino 			    info->pi_provider_description);
379d3b2efc7SAnthony Scarpino 			break;
380d3b2efc7SAnthony Scarpino 
381d3b2efc7SAnthony Scarpino 		case CRYPTO_MODVERIFICATION_FAILED:
382d3b2efc7SAnthony Scarpino 			cmn_err(CE_WARN, "%s failed module verification when "
383d3b2efc7SAnthony Scarpino 			    "registering with the Cryptographic Framework.",
384d3b2efc7SAnthony Scarpino 			    info->pi_provider_description);
385d3b2efc7SAnthony Scarpino 			break;
386d3b2efc7SAnthony Scarpino 
387d3b2efc7SAnthony Scarpino 		case CRYPTO_ARGUMENTS_BAD:
388d3b2efc7SAnthony Scarpino 			cmn_err(CE_WARN, "%s provided bad arguments and was "
389d3b2efc7SAnthony Scarpino 			    "not registered with the Cryptographic Framework.",
390d3b2efc7SAnthony Scarpino 			    info->pi_provider_description);
391d3b2efc7SAnthony Scarpino 			break;
392d3b2efc7SAnthony Scarpino 
393d3b2efc7SAnthony Scarpino 		case CRYPTO_VERSION_MISMATCH:
394d3b2efc7SAnthony Scarpino 			cmn_err(CE_WARN, "%s was not registered with the "
395d3b2efc7SAnthony Scarpino 			    "Cryptographic Framework as there is a SPI version "
396d3b2efc7SAnthony Scarpino 			    "mismatch (%d) error.",
397d3b2efc7SAnthony Scarpino 			    info->pi_provider_description,
398d3b2efc7SAnthony Scarpino 			    info->pi_interface_version);
399d3b2efc7SAnthony Scarpino 			break;
400d3b2efc7SAnthony Scarpino 
401d3b2efc7SAnthony Scarpino 		case CRYPTO_FIPS140_ERROR:
402d3b2efc7SAnthony Scarpino 			cmn_err(CE_WARN, "%s was not registered with the "
403d3b2efc7SAnthony Scarpino 			    "Cryptographic Framework as there was a FIPS 140 "
404d3b2efc7SAnthony Scarpino 			    "validation error.", info->pi_provider_description);
405d3b2efc7SAnthony Scarpino 			break;
406d3b2efc7SAnthony Scarpino 
407d3b2efc7SAnthony Scarpino 		default:
408d3b2efc7SAnthony Scarpino 			cmn_err(CE_WARN, "%s did not register with the "
409d3b2efc7SAnthony Scarpino 			    "Cryptographic Framework. (0x%x)",
410d3b2efc7SAnthony Scarpino 			    info->pi_provider_description, ret);
411d3b2efc7SAnthony Scarpino 		};
412d3b2efc7SAnthony Scarpino 	}
413d3b2efc7SAnthony Scarpino 
4147c478bd9Sstevel@tonic-gate 	return (ret);
4157c478bd9Sstevel@tonic-gate }
4167c478bd9Sstevel@tonic-gate 
417ef56a3c5SKrishna Yenduri /* Return the number of holds on a provider. */
418ef56a3c5SKrishna Yenduri int
419ef56a3c5SKrishna Yenduri kcf_get_refcnt(kcf_provider_desc_t *pd, boolean_t do_lock)
420ef56a3c5SKrishna Yenduri {
421ef56a3c5SKrishna Yenduri 	int i;
422ef56a3c5SKrishna Yenduri 	int refcnt = 0;
423ef56a3c5SKrishna Yenduri 
424ef56a3c5SKrishna Yenduri 	if (do_lock)
425ef56a3c5SKrishna Yenduri 		for (i = 0; i < pd->pd_nbins; i++)
426ef56a3c5SKrishna Yenduri 			mutex_enter(&(pd->pd_percpu_bins[i].kp_lock));
427ef56a3c5SKrishna Yenduri 
428ef56a3c5SKrishna Yenduri 	for (i = 0; i < pd->pd_nbins; i++)
429ef56a3c5SKrishna Yenduri 		refcnt += pd->pd_percpu_bins[i].kp_holdcnt;
430ef56a3c5SKrishna Yenduri 
431ef56a3c5SKrishna Yenduri 	if (do_lock)
432ef56a3c5SKrishna Yenduri 		for (i = 0; i < pd->pd_nbins; i++)
433ef56a3c5SKrishna Yenduri 			mutex_exit(&(pd->pd_percpu_bins[i].kp_lock));
434ef56a3c5SKrishna Yenduri 
435ef56a3c5SKrishna Yenduri 	return (refcnt);
436ef56a3c5SKrishna Yenduri }
437ef56a3c5SKrishna Yenduri 
4387c478bd9Sstevel@tonic-gate /*
4397c478bd9Sstevel@tonic-gate  * This routine is used to notify the framework when a provider is being
4407c478bd9Sstevel@tonic-gate  * removed.  Hardware providers call this routine in their detach routines.
4417c478bd9Sstevel@tonic-gate  * Software providers call this routine in their _fini() routine.
4427c478bd9Sstevel@tonic-gate  */
4437c478bd9Sstevel@tonic-gate int
4447c478bd9Sstevel@tonic-gate crypto_unregister_provider(crypto_kcf_provider_handle_t handle)
4457c478bd9Sstevel@tonic-gate {
4467c478bd9Sstevel@tonic-gate 	uint_t mech_idx;
4477c478bd9Sstevel@tonic-gate 	kcf_provider_desc_t *desc;
4487c478bd9Sstevel@tonic-gate 	kcf_prov_state_t saved_state;
449d3b2efc7SAnthony Scarpino 	int ret = CRYPTO_SUCCESS;
4507c478bd9Sstevel@tonic-gate 
4517c478bd9Sstevel@tonic-gate 	/* lookup provider descriptor */
452d3b2efc7SAnthony Scarpino 	if ((desc = kcf_prov_tab_lookup((crypto_provider_id_t)handle)) ==
453d3b2efc7SAnthony Scarpino 	    NULL) {
454d3b2efc7SAnthony Scarpino 		ret = CRYPTO_UNKNOWN_PROVIDER;
455d3b2efc7SAnthony Scarpino 		goto errormsg;
456d3b2efc7SAnthony Scarpino 	}
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate 	mutex_enter(&desc->pd_lock);
4597c478bd9Sstevel@tonic-gate 	/*
4607c478bd9Sstevel@tonic-gate 	 * Check if any other thread is disabling or removing
4617c478bd9Sstevel@tonic-gate 	 * this provider. We return if this is the case.
4627c478bd9Sstevel@tonic-gate 	 */
4637c478bd9Sstevel@tonic-gate 	if (desc->pd_state >= KCF_PROV_DISABLED) {
4647c478bd9Sstevel@tonic-gate 		mutex_exit(&desc->pd_lock);
4657c478bd9Sstevel@tonic-gate 		/* Release reference held by kcf_prov_tab_lookup(). */
4667c478bd9Sstevel@tonic-gate 		KCF_PROV_REFRELE(desc);
467d3b2efc7SAnthony Scarpino 		ret = CRYPTO_BUSY;
468d3b2efc7SAnthony Scarpino 		goto errormsg;
4697c478bd9Sstevel@tonic-gate 	}
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 	saved_state = desc->pd_state;
472ef56a3c5SKrishna Yenduri 	desc->pd_state = KCF_PROV_UNREGISTERING;
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate 	if (saved_state == KCF_PROV_BUSY) {
4757c478bd9Sstevel@tonic-gate 		/*
47668468c97Skrishna 		 * The per-provider taskq threads may be waiting. We
47768468c97Skrishna 		 * signal them so that they can start failing requests.
4787c478bd9Sstevel@tonic-gate 		 */
47968468c97Skrishna 		cv_broadcast(&desc->pd_resume_cv);
4807c478bd9Sstevel@tonic-gate 	}
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate 	mutex_exit(&desc->pd_lock);
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate 	if (desc->pd_prov_type != CRYPTO_SW_PROVIDER) {
4857c478bd9Sstevel@tonic-gate 		remove_provider(desc);
4867c478bd9Sstevel@tonic-gate 	}
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate 	if (desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) {
4897c478bd9Sstevel@tonic-gate 		/* remove the provider from the mechanisms tables */
4907c478bd9Sstevel@tonic-gate 		for (mech_idx = 0; mech_idx < desc->pd_mech_list_count;
4917c478bd9Sstevel@tonic-gate 		    mech_idx++) {
4927c478bd9Sstevel@tonic-gate 			kcf_remove_mech_provider(
4937c478bd9Sstevel@tonic-gate 			    desc->pd_mechanisms[mech_idx].cm_mech_name, desc);
4947c478bd9Sstevel@tonic-gate 		}
4957c478bd9Sstevel@tonic-gate 	}
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 	/* remove provider from providers table */
4987c478bd9Sstevel@tonic-gate 	if (kcf_prov_tab_rem_provider((crypto_provider_id_t)handle) !=
4997c478bd9Sstevel@tonic-gate 	    CRYPTO_SUCCESS) {
5007c478bd9Sstevel@tonic-gate 		/* Release reference held by kcf_prov_tab_lookup(). */
5017c478bd9Sstevel@tonic-gate 		KCF_PROV_REFRELE(desc);
502d3b2efc7SAnthony Scarpino 		ret = CRYPTO_UNKNOWN_PROVIDER;
503d3b2efc7SAnthony Scarpino 		goto errormsg;
5047c478bd9Sstevel@tonic-gate 	}
5057c478bd9Sstevel@tonic-gate 
506fe2f7468Skrishna 	delete_kstat(desc);
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate 	if (desc->pd_prov_type == CRYPTO_SW_PROVIDER) {
5097c478bd9Sstevel@tonic-gate 		/*
510ef56a3c5SKrishna Yenduri 		 * Wait till the existing requests with the provider complete
511ef56a3c5SKrishna Yenduri 		 * and all the holds are released. All the holds on a software
512ef56a3c5SKrishna Yenduri 		 * provider are from kernel clients and the hold time
513ef56a3c5SKrishna Yenduri 		 * is expected to be short. So, we won't be stuck here forever.
5147c478bd9Sstevel@tonic-gate 		 */
515ef56a3c5SKrishna Yenduri 		while (kcf_get_refcnt(desc, B_TRUE) > 1) {
516ef56a3c5SKrishna Yenduri 			/* wait 1 second and try again. */
517ef56a3c5SKrishna Yenduri 			delay(1 * drv_usectohz(1000000));
518ef56a3c5SKrishna Yenduri 		}
5197c478bd9Sstevel@tonic-gate 	} else {
520ef56a3c5SKrishna Yenduri 		int i;
521ef56a3c5SKrishna Yenduri 		kcf_prov_cpu_t *mp;
522ef56a3c5SKrishna Yenduri 
5237c478bd9Sstevel@tonic-gate 		/*
5247c478bd9Sstevel@tonic-gate 		 * Wait until requests that have been sent to the provider
5257c478bd9Sstevel@tonic-gate 		 * complete.
5267c478bd9Sstevel@tonic-gate 		 */
527ef56a3c5SKrishna Yenduri 		for (i = 0; i < desc->pd_nbins; i++) {
528ef56a3c5SKrishna Yenduri 			mp = &(desc->pd_percpu_bins[i]);
529ef56a3c5SKrishna Yenduri 
530ef56a3c5SKrishna Yenduri 			mutex_enter(&mp->kp_lock);
531ef56a3c5SKrishna Yenduri 			while (mp->kp_jobcnt > 0) {
532ef56a3c5SKrishna Yenduri 				cv_wait(&mp->kp_cv, &mp->kp_lock);
5337c478bd9Sstevel@tonic-gate 			}
534ef56a3c5SKrishna Yenduri 			mutex_exit(&mp->kp_lock);
535ef56a3c5SKrishna Yenduri 		}
536ef56a3c5SKrishna Yenduri 	}
537ef56a3c5SKrishna Yenduri 
538ef56a3c5SKrishna Yenduri 	mutex_enter(&desc->pd_lock);
539ef56a3c5SKrishna Yenduri 	desc->pd_state = KCF_PROV_UNREGISTERED;
540ef56a3c5SKrishna Yenduri 	mutex_exit(&desc->pd_lock);
5417c478bd9Sstevel@tonic-gate 
542fe2f7468Skrishna 	kcf_do_notify(desc, B_FALSE);
543c892ebf1Skrishna 
5447623016fSKrishna Yenduri 	mutex_enter(&prov_tab_mutex);
545ef56a3c5SKrishna Yenduri 	/* Release reference held by kcf_prov_tab_lookup(). */
546ef56a3c5SKrishna Yenduri 	KCF_PROV_REFRELE(desc);
547ef56a3c5SKrishna Yenduri 
548ef56a3c5SKrishna Yenduri 	if (kcf_get_refcnt(desc, B_TRUE) == 0) {
5497623016fSKrishna Yenduri 		/* kcf_free_provider_desc drops prov_tab_mutex */
5507c478bd9Sstevel@tonic-gate 		kcf_free_provider_desc(desc);
5517c478bd9Sstevel@tonic-gate 	} else {
552ef56a3c5SKrishna Yenduri 		ASSERT(desc->pd_prov_type != CRYPTO_SW_PROVIDER);
553ef56a3c5SKrishna Yenduri 		/*
554ef56a3c5SKrishna Yenduri 		 * We could avoid this if /dev/crypto can proactively
555ef56a3c5SKrishna Yenduri 		 * remove any holds on us from a dormant PKCS #11 app.
5567623016fSKrishna Yenduri 		 * For now, we check the provider table for
5577623016fSKrishna Yenduri 		 * KCF_PROV_UNREGISTERED entries when a provider is
5587623016fSKrishna Yenduri 		 * added to the table or when a provider is removed from it
5597623016fSKrishna Yenduri 		 * and free them when refcnt reaches zero.
560ef56a3c5SKrishna Yenduri 		 */
561ef56a3c5SKrishna Yenduri 		kcf_need_provtab_walk = B_TRUE;
562ef56a3c5SKrishna Yenduri 		mutex_exit(&prov_tab_mutex);
5637c478bd9Sstevel@tonic-gate 	}
5647c478bd9Sstevel@tonic-gate 
565d3b2efc7SAnthony Scarpino errormsg:
566d3b2efc7SAnthony Scarpino 	if (ret != CRYPTO_SUCCESS && sys_shutdown == 0) {
567d3b2efc7SAnthony Scarpino 		switch (ret) {
568d3b2efc7SAnthony Scarpino 		case CRYPTO_UNKNOWN_PROVIDER:
569d3b2efc7SAnthony Scarpino 			cmn_err(CE_WARN, "Unknown provider \"%s\" was "
570d3b2efc7SAnthony Scarpino 			    "requested to unregister from the cryptographic "
571d3b2efc7SAnthony Scarpino 			    "framework.", desc->pd_description);
572d3b2efc7SAnthony Scarpino 			break;
573d3b2efc7SAnthony Scarpino 
574d3b2efc7SAnthony Scarpino 		case CRYPTO_BUSY:
575d3b2efc7SAnthony Scarpino 			cmn_err(CE_WARN, "%s could not be unregistered from "
576d3b2efc7SAnthony Scarpino 			    "the Cryptographic Framework as it is busy.",
577d3b2efc7SAnthony Scarpino 			    desc->pd_description);
578d3b2efc7SAnthony Scarpino 			break;
579d3b2efc7SAnthony Scarpino 
580d3b2efc7SAnthony Scarpino 		default:
581d3b2efc7SAnthony Scarpino 			cmn_err(CE_WARN, "%s did not unregister with the "
582d3b2efc7SAnthony Scarpino 			    "Cryptographic Framework. (0x%x)",
583d3b2efc7SAnthony Scarpino 			    desc->pd_description, ret);
584d3b2efc7SAnthony Scarpino 		};
585d3b2efc7SAnthony Scarpino 	}
586d3b2efc7SAnthony Scarpino 
587d3b2efc7SAnthony Scarpino 	return (ret);
5887c478bd9Sstevel@tonic-gate }
5897c478bd9Sstevel@tonic-gate 
5907c478bd9Sstevel@tonic-gate /*
5917c478bd9Sstevel@tonic-gate  * This routine is used to notify the framework that the state of
5927c478bd9Sstevel@tonic-gate  * a cryptographic provider has changed. Valid state codes are:
5937c478bd9Sstevel@tonic-gate  *
5947c478bd9Sstevel@tonic-gate  * CRYPTO_PROVIDER_READY
5957c478bd9Sstevel@tonic-gate  * 	The provider indicates that it can process more requests. A provider
5967c478bd9Sstevel@tonic-gate  *	will notify with this event if it previously has notified us with a
5977c478bd9Sstevel@tonic-gate  *	CRYPTO_PROVIDER_BUSY.
5987c478bd9Sstevel@tonic-gate  *
5997c478bd9Sstevel@tonic-gate  * CRYPTO_PROVIDER_BUSY
6007c478bd9Sstevel@tonic-gate  * 	The provider can not take more requests.
6017c478bd9Sstevel@tonic-gate  *
6027c478bd9Sstevel@tonic-gate  * CRYPTO_PROVIDER_FAILED
6037c478bd9Sstevel@tonic-gate  *	The provider encountered an internal error. The framework will not
6047c478bd9Sstevel@tonic-gate  * 	be sending any more requests to the provider. The provider may notify
6057c478bd9Sstevel@tonic-gate  *	with a CRYPTO_PROVIDER_READY, if it is able to recover from the error.
6067c478bd9Sstevel@tonic-gate  *
6077c478bd9Sstevel@tonic-gate  * This routine can be called from user or interrupt context.
6087c478bd9Sstevel@tonic-gate  */
6097c478bd9Sstevel@tonic-gate void
6107c478bd9Sstevel@tonic-gate crypto_provider_notification(crypto_kcf_provider_handle_t handle, uint_t state)
6117c478bd9Sstevel@tonic-gate {
6127c478bd9Sstevel@tonic-gate 	kcf_provider_desc_t *pd;
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate 	/* lookup the provider from the given handle */
6157c478bd9Sstevel@tonic-gate 	if ((pd = kcf_prov_tab_lookup((crypto_provider_id_t)handle)) == NULL)
6167c478bd9Sstevel@tonic-gate 		return;
6177c478bd9Sstevel@tonic-gate 
6187c478bd9Sstevel@tonic-gate 	mutex_enter(&pd->pd_lock);
6197c478bd9Sstevel@tonic-gate 
620fe2f7468Skrishna 	if (pd->pd_state <= KCF_PROV_VERIFICATION_FAILED)
621fe2f7468Skrishna 		goto out;
622fe2f7468Skrishna 
6237c478bd9Sstevel@tonic-gate 	if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
6247c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "crypto_provider_notification: "
6257c478bd9Sstevel@tonic-gate 		    "logical provider (%x) ignored\n", handle);
6267c478bd9Sstevel@tonic-gate 		goto out;
6277c478bd9Sstevel@tonic-gate 	}
6287c478bd9Sstevel@tonic-gate 	switch (state) {
6297c478bd9Sstevel@tonic-gate 	case CRYPTO_PROVIDER_READY:
6307c478bd9Sstevel@tonic-gate 		switch (pd->pd_state) {
6317c478bd9Sstevel@tonic-gate 		case KCF_PROV_BUSY:
6327c478bd9Sstevel@tonic-gate 			pd->pd_state = KCF_PROV_READY;
6337c478bd9Sstevel@tonic-gate 			/*
63468468c97Skrishna 			 * Signal the per-provider taskq threads that they
63568468c97Skrishna 			 * can start submitting requests.
6367c478bd9Sstevel@tonic-gate 			 */
63768468c97Skrishna 			cv_broadcast(&pd->pd_resume_cv);
6387c478bd9Sstevel@tonic-gate 			break;
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate 		case KCF_PROV_FAILED:
6417c478bd9Sstevel@tonic-gate 			/*
6427c478bd9Sstevel@tonic-gate 			 * The provider recovered from the error. Let us
6437c478bd9Sstevel@tonic-gate 			 * use it now.
6447c478bd9Sstevel@tonic-gate 			 */
6457c478bd9Sstevel@tonic-gate 			pd->pd_state = KCF_PROV_READY;
6467c478bd9Sstevel@tonic-gate 			break;
6477c478bd9Sstevel@tonic-gate 		}
6487c478bd9Sstevel@tonic-gate 		break;
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate 	case CRYPTO_PROVIDER_BUSY:
6517c478bd9Sstevel@tonic-gate 		switch (pd->pd_state) {
6527c478bd9Sstevel@tonic-gate 		case KCF_PROV_READY:
6537c478bd9Sstevel@tonic-gate 			pd->pd_state = KCF_PROV_BUSY;
6547c478bd9Sstevel@tonic-gate 			break;
6557c478bd9Sstevel@tonic-gate 		}
6567c478bd9Sstevel@tonic-gate 		break;
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate 	case CRYPTO_PROVIDER_FAILED:
6597c478bd9Sstevel@tonic-gate 		/*
6607c478bd9Sstevel@tonic-gate 		 * We note the failure and return. The per-provider taskq
66168468c97Skrishna 		 * threads check this flag and start failing the
6627c478bd9Sstevel@tonic-gate 		 * requests, if it is set. See process_req_hwp() for details.
6637c478bd9Sstevel@tonic-gate 		 */
6647c478bd9Sstevel@tonic-gate 		switch (pd->pd_state) {
6657c478bd9Sstevel@tonic-gate 		case KCF_PROV_READY:
6667c478bd9Sstevel@tonic-gate 			pd->pd_state = KCF_PROV_FAILED;
6677c478bd9Sstevel@tonic-gate 			break;
6687c478bd9Sstevel@tonic-gate 
6697c478bd9Sstevel@tonic-gate 		case KCF_PROV_BUSY:
6707c478bd9Sstevel@tonic-gate 			pd->pd_state = KCF_PROV_FAILED;
6717c478bd9Sstevel@tonic-gate 			/*
67268468c97Skrishna 			 * The per-provider taskq threads may be waiting. We
67368468c97Skrishna 			 * signal them so that they can start failing requests.
6747c478bd9Sstevel@tonic-gate 			 */
67568468c97Skrishna 			cv_broadcast(&pd->pd_resume_cv);
6767c478bd9Sstevel@tonic-gate 			break;
6777c478bd9Sstevel@tonic-gate 		}
6787c478bd9Sstevel@tonic-gate 		break;
6797c478bd9Sstevel@tonic-gate 	}
6807c478bd9Sstevel@tonic-gate out:
6817c478bd9Sstevel@tonic-gate 	mutex_exit(&pd->pd_lock);
6827c478bd9Sstevel@tonic-gate 	KCF_PROV_REFRELE(pd);
6837c478bd9Sstevel@tonic-gate }
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate /*
6867c478bd9Sstevel@tonic-gate  * This routine is used to notify the framework the result of
6877c478bd9Sstevel@tonic-gate  * an asynchronous request handled by a provider. Valid error
6887c478bd9Sstevel@tonic-gate  * codes are the same as the CRYPTO_* errors defined in common.h.
6897c478bd9Sstevel@tonic-gate  *
6907c478bd9Sstevel@tonic-gate  * This routine can be called from user or interrupt context.
6917c478bd9Sstevel@tonic-gate  */
6927c478bd9Sstevel@tonic-gate void
6937c478bd9Sstevel@tonic-gate crypto_op_notification(crypto_req_handle_t handle, int error)
6947c478bd9Sstevel@tonic-gate {
6957c478bd9Sstevel@tonic-gate 	kcf_call_type_t ctype;
6967c478bd9Sstevel@tonic-gate 
697c1591d22SKrishna Yenduri 	if (handle == NULL)
698c1591d22SKrishna Yenduri 		return;
699c1591d22SKrishna Yenduri 
7007c478bd9Sstevel@tonic-gate 	if ((ctype = GET_REQ_TYPE(handle)) == CRYPTO_SYNCH) {
7017c478bd9Sstevel@tonic-gate 		kcf_sreq_node_t *sreq = (kcf_sreq_node_t *)handle;
7027c478bd9Sstevel@tonic-gate 
703ef56a3c5SKrishna Yenduri 		KCF_PROV_JOB_RELE_STAT(sreq->sn_mp, (error != CRYPTO_SUCCESS));
7047c478bd9Sstevel@tonic-gate 		kcf_sop_done(sreq, error);
7057c478bd9Sstevel@tonic-gate 	} else {
7067c478bd9Sstevel@tonic-gate 		kcf_areq_node_t *areq = (kcf_areq_node_t *)handle;
7077c478bd9Sstevel@tonic-gate 
7087c478bd9Sstevel@tonic-gate 		ASSERT(ctype == CRYPTO_ASYNCH);
709ef56a3c5SKrishna Yenduri 		KCF_PROV_JOB_RELE_STAT(areq->an_mp, (error != CRYPTO_SUCCESS));
7107c478bd9Sstevel@tonic-gate 		kcf_aop_done(areq, error);
7117c478bd9Sstevel@tonic-gate 	}
7127c478bd9Sstevel@tonic-gate }
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate /*
7157c478bd9Sstevel@tonic-gate  * This routine is used by software providers to determine
7167c478bd9Sstevel@tonic-gate  * whether to use KM_SLEEP or KM_NOSLEEP during memory allocation.
7177c478bd9Sstevel@tonic-gate  * Note that hardware providers can always use KM_SLEEP. So,
7187c478bd9Sstevel@tonic-gate  * they do not need to call this routine.
7197c478bd9Sstevel@tonic-gate  *
7207c478bd9Sstevel@tonic-gate  * This routine can be called from user or interrupt context.
7217c478bd9Sstevel@tonic-gate  */
7227c478bd9Sstevel@tonic-gate int
7237c478bd9Sstevel@tonic-gate crypto_kmflag(crypto_req_handle_t handle)
7247c478bd9Sstevel@tonic-gate {
7257c478bd9Sstevel@tonic-gate 	return (REQHNDL2_KMFLAG(handle));
7267c478bd9Sstevel@tonic-gate }
7277c478bd9Sstevel@tonic-gate 
7287c478bd9Sstevel@tonic-gate /*
7297c478bd9Sstevel@tonic-gate  * Process the mechanism info structures specified by the provider
7307c478bd9Sstevel@tonic-gate  * during registration. A NULL crypto_provider_info_t indicates
7317c478bd9Sstevel@tonic-gate  * an already initialized provider descriptor.
7327c478bd9Sstevel@tonic-gate  *
7337c478bd9Sstevel@tonic-gate  * Mechanisms are not added to the kernel's mechanism table if the
7347c478bd9Sstevel@tonic-gate  * provider is a logical provider.
7357c478bd9Sstevel@tonic-gate  *
7367c478bd9Sstevel@tonic-gate  * Returns CRYPTO_SUCCESS on success, CRYPTO_ARGUMENTS if one
7377c478bd9Sstevel@tonic-gate  * of the specified mechanisms was malformed, or CRYPTO_HOST_MEMORY
7387c478bd9Sstevel@tonic-gate  * if the table of mechanisms is full.
7397c478bd9Sstevel@tonic-gate  */
7407c478bd9Sstevel@tonic-gate static int
7417c478bd9Sstevel@tonic-gate init_prov_mechs(crypto_provider_info_t *info, kcf_provider_desc_t *desc)
7427c478bd9Sstevel@tonic-gate {
7437c478bd9Sstevel@tonic-gate 	uint_t mech_idx;
7447c478bd9Sstevel@tonic-gate 	uint_t cleanup_idx;
7457c478bd9Sstevel@tonic-gate 	int err = CRYPTO_SUCCESS;
7467c478bd9Sstevel@tonic-gate 	kcf_prov_mech_desc_t *pmd;
7477c478bd9Sstevel@tonic-gate 	int desc_use_count = 0;
7487c478bd9Sstevel@tonic-gate 	int mcount = desc->pd_mech_list_count;
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate 	if (desc->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
7517c478bd9Sstevel@tonic-gate 		if (info != NULL) {
7527c478bd9Sstevel@tonic-gate 			ASSERT(info->pi_mechanisms != NULL);
7537c478bd9Sstevel@tonic-gate 			bcopy(info->pi_mechanisms, desc->pd_mechanisms,
7547c478bd9Sstevel@tonic-gate 			    sizeof (crypto_mech_info_t) * mcount);
7557c478bd9Sstevel@tonic-gate 		}
7567c478bd9Sstevel@tonic-gate 		return (CRYPTO_SUCCESS);
7577c478bd9Sstevel@tonic-gate 	}
7587c478bd9Sstevel@tonic-gate 
7597c478bd9Sstevel@tonic-gate 	/*
7607c478bd9Sstevel@tonic-gate 	 * Copy the mechanism list from the provider info to the provider
7617c478bd9Sstevel@tonic-gate 	 * descriptor. desc->pd_mechanisms has an extra crypto_mech_info_t
7627c478bd9Sstevel@tonic-gate 	 * element if the provider has random_ops since we keep an internal
7637c478bd9Sstevel@tonic-gate 	 * mechanism, SUN_RANDOM, in this case.
7647c478bd9Sstevel@tonic-gate 	 */
7657c478bd9Sstevel@tonic-gate 	if (info != NULL) {
766894b2776Smcpowers 		if (info->pi_ops_vector->co_random_ops != NULL) {
7677c478bd9Sstevel@tonic-gate 			crypto_mech_info_t *rand_mi;
7687c478bd9Sstevel@tonic-gate 
7697c478bd9Sstevel@tonic-gate 			/*
7707c478bd9Sstevel@tonic-gate 			 * Need the following check as it is possible to have
7717c478bd9Sstevel@tonic-gate 			 * a provider that implements just random_ops and has
7727c478bd9Sstevel@tonic-gate 			 * pi_mechanisms == NULL.
7737c478bd9Sstevel@tonic-gate 			 */
7747c478bd9Sstevel@tonic-gate 			if (info->pi_mechanisms != NULL) {
7757c478bd9Sstevel@tonic-gate 				bcopy(info->pi_mechanisms, desc->pd_mechanisms,
7767c478bd9Sstevel@tonic-gate 				    sizeof (crypto_mech_info_t) * (mcount - 1));
7777c478bd9Sstevel@tonic-gate 			}
7787c478bd9Sstevel@tonic-gate 			rand_mi = &desc->pd_mechanisms[mcount - 1];
7797c478bd9Sstevel@tonic-gate 
7807c478bd9Sstevel@tonic-gate 			bzero(rand_mi, sizeof (crypto_mech_info_t));
7817c478bd9Sstevel@tonic-gate 			(void) strncpy(rand_mi->cm_mech_name, SUN_RANDOM,
7827c478bd9Sstevel@tonic-gate 			    CRYPTO_MAX_MECH_NAME);
7837c478bd9Sstevel@tonic-gate 			rand_mi->cm_func_group_mask = CRYPTO_FG_RANDOM;
7847c478bd9Sstevel@tonic-gate 		} else {
7857c478bd9Sstevel@tonic-gate 			ASSERT(info->pi_mechanisms != NULL);
7867c478bd9Sstevel@tonic-gate 			bcopy(info->pi_mechanisms, desc->pd_mechanisms,
7877c478bd9Sstevel@tonic-gate 			    sizeof (crypto_mech_info_t) * mcount);
7887c478bd9Sstevel@tonic-gate 		}
7897c478bd9Sstevel@tonic-gate 	}
7907c478bd9Sstevel@tonic-gate 
7917c478bd9Sstevel@tonic-gate 	/*
7927c478bd9Sstevel@tonic-gate 	 * For each mechanism support by the provider, add the provider
7937c478bd9Sstevel@tonic-gate 	 * to the corresponding KCF mechanism mech_entry chain.
7947c478bd9Sstevel@tonic-gate 	 */
7957c478bd9Sstevel@tonic-gate 	for (mech_idx = 0; mech_idx < desc->pd_mech_list_count; mech_idx++) {
7967c478bd9Sstevel@tonic-gate 		crypto_mech_info_t *mi = &desc->pd_mechanisms[mech_idx];
7977c478bd9Sstevel@tonic-gate 
7986a1073f8Skrishna 		if ((mi->cm_mech_flags & CRYPTO_KEYSIZE_UNIT_IN_BITS) &&
7996a1073f8Skrishna 		    (mi->cm_mech_flags & CRYPTO_KEYSIZE_UNIT_IN_BYTES)) {
8007c478bd9Sstevel@tonic-gate 			err = CRYPTO_ARGUMENTS_BAD;
8017c478bd9Sstevel@tonic-gate 			break;
8027c478bd9Sstevel@tonic-gate 		}
8037c478bd9Sstevel@tonic-gate 
804c1591d22SKrishna Yenduri 		if ((err = kcf_add_mech_provider(mech_idx, desc, &pmd)) !=
805c1591d22SKrishna Yenduri 		    KCF_SUCCESS)
8067c478bd9Sstevel@tonic-gate 			break;
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate 		if (pmd == NULL)
8097c478bd9Sstevel@tonic-gate 			continue;
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate 		/* The provider will be used for this mechanism */
8127c478bd9Sstevel@tonic-gate 		desc_use_count++;
8137c478bd9Sstevel@tonic-gate 	}
8147c478bd9Sstevel@tonic-gate 
8157c478bd9Sstevel@tonic-gate 	/*
8167ce878deSmcpowers 	 * Don't allow multiple software providers with disabled mechanisms
8177ce878deSmcpowers 	 * to register. Subsequent enabling of mechanisms will result in
8187ce878deSmcpowers 	 * an unsupported configuration, i.e. multiple software providers
8197ce878deSmcpowers 	 * per mechanism.
8207c478bd9Sstevel@tonic-gate 	 */
8217ce878deSmcpowers 	if (desc_use_count == 0 && desc->pd_prov_type == CRYPTO_SW_PROVIDER)
8227c478bd9Sstevel@tonic-gate 		return (CRYPTO_ARGUMENTS_BAD);
8237c478bd9Sstevel@tonic-gate 
8247c478bd9Sstevel@tonic-gate 	if (err == KCF_SUCCESS)
8257c478bd9Sstevel@tonic-gate 		return (CRYPTO_SUCCESS);
8267c478bd9Sstevel@tonic-gate 
8277c478bd9Sstevel@tonic-gate 	/*
8287c478bd9Sstevel@tonic-gate 	 * An error occurred while adding the mechanism, cleanup
8297c478bd9Sstevel@tonic-gate 	 * and bail.
8307c478bd9Sstevel@tonic-gate 	 */
8317c478bd9Sstevel@tonic-gate 	for (cleanup_idx = 0; cleanup_idx < mech_idx; cleanup_idx++) {
8327c478bd9Sstevel@tonic-gate 		kcf_remove_mech_provider(
8337c478bd9Sstevel@tonic-gate 		    desc->pd_mechanisms[cleanup_idx].cm_mech_name, desc);
8347c478bd9Sstevel@tonic-gate 	}
8357c478bd9Sstevel@tonic-gate 
8367c478bd9Sstevel@tonic-gate 	if (err == KCF_MECH_TAB_FULL)
8377c478bd9Sstevel@tonic-gate 		return (CRYPTO_HOST_MEMORY);
8387c478bd9Sstevel@tonic-gate 
8397c478bd9Sstevel@tonic-gate 	return (CRYPTO_ARGUMENTS_BAD);
8407c478bd9Sstevel@tonic-gate }
8417c478bd9Sstevel@tonic-gate 
8427c478bd9Sstevel@tonic-gate /*
8437c478bd9Sstevel@tonic-gate  * Update routine for kstat. Only privileged users are allowed to
8447c478bd9Sstevel@tonic-gate  * access this information, since this information is sensitive.
8457c478bd9Sstevel@tonic-gate  * There are some cryptographic attacks (e.g. traffic analysis)
8467c478bd9Sstevel@tonic-gate  * which can use this information.
8477c478bd9Sstevel@tonic-gate  */
8487c478bd9Sstevel@tonic-gate static int
8497c478bd9Sstevel@tonic-gate kcf_prov_kstat_update(kstat_t *ksp, int rw)
8507c478bd9Sstevel@tonic-gate {
8517c478bd9Sstevel@tonic-gate 	kcf_prov_stats_t *ks_data;
8527c478bd9Sstevel@tonic-gate 	kcf_provider_desc_t *pd = (kcf_provider_desc_t *)ksp->ks_private;
853ef56a3c5SKrishna Yenduri 	int i;
8547c478bd9Sstevel@tonic-gate 
8557c478bd9Sstevel@tonic-gate 	if (rw == KSTAT_WRITE)
8567c478bd9Sstevel@tonic-gate 		return (EACCES);
8577c478bd9Sstevel@tonic-gate 
8587c478bd9Sstevel@tonic-gate 	ks_data = ksp->ks_data;
8597c478bd9Sstevel@tonic-gate 
8607c478bd9Sstevel@tonic-gate 	if (secpolicy_sys_config(CRED(), B_TRUE) != 0) {
8617c478bd9Sstevel@tonic-gate 		ks_data->ps_ops_total.value.ui64 = 0;
8627c478bd9Sstevel@tonic-gate 		ks_data->ps_ops_passed.value.ui64 = 0;
8637c478bd9Sstevel@tonic-gate 		ks_data->ps_ops_failed.value.ui64 = 0;
8647c478bd9Sstevel@tonic-gate 		ks_data->ps_ops_busy_rval.value.ui64 = 0;
8657c478bd9Sstevel@tonic-gate 	} else {
866ef56a3c5SKrishna Yenduri 		uint64_t dtotal, ftotal, btotal;
867ef56a3c5SKrishna Yenduri 
868ef56a3c5SKrishna Yenduri 		dtotal = ftotal = btotal = 0;
869ef56a3c5SKrishna Yenduri 		/* No locking done since an exact count is not required. */
870ef56a3c5SKrishna Yenduri 		for (i = 0; i < pd->pd_nbins; i++) {
871ef56a3c5SKrishna Yenduri 			dtotal += pd->pd_percpu_bins[i].kp_ndispatches;
872ef56a3c5SKrishna Yenduri 			ftotal += pd->pd_percpu_bins[i].kp_nfails;
873ef56a3c5SKrishna Yenduri 			btotal += pd->pd_percpu_bins[i].kp_nbusy_rval;
874ef56a3c5SKrishna Yenduri 		}
875ef56a3c5SKrishna Yenduri 
876ef56a3c5SKrishna Yenduri 		ks_data->ps_ops_total.value.ui64 = dtotal;
877ef56a3c5SKrishna Yenduri 		ks_data->ps_ops_failed.value.ui64 = ftotal;
878ef56a3c5SKrishna Yenduri 		ks_data->ps_ops_busy_rval.value.ui64 = btotal;
879ef56a3c5SKrishna Yenduri 		ks_data->ps_ops_passed.value.ui64 = dtotal - ftotal - btotal;
8807c478bd9Sstevel@tonic-gate 	}
8817c478bd9Sstevel@tonic-gate 
8827c478bd9Sstevel@tonic-gate 	return (0);
8837c478bd9Sstevel@tonic-gate }
8847c478bd9Sstevel@tonic-gate 
8857c478bd9Sstevel@tonic-gate 
8867c478bd9Sstevel@tonic-gate /*
8877c478bd9Sstevel@tonic-gate  * Utility routine called from failure paths in crypto_register_provider()
8887c478bd9Sstevel@tonic-gate  * and from crypto_load_soft_disabled().
8897c478bd9Sstevel@tonic-gate  */
8907c478bd9Sstevel@tonic-gate void
8917c478bd9Sstevel@tonic-gate undo_register_provider(kcf_provider_desc_t *desc, boolean_t remove_prov)
8927c478bd9Sstevel@tonic-gate {
8937c478bd9Sstevel@tonic-gate 	uint_t mech_idx;
8947c478bd9Sstevel@tonic-gate 
8957c478bd9Sstevel@tonic-gate 	/* remove the provider from the mechanisms tables */
8967c478bd9Sstevel@tonic-gate 	for (mech_idx = 0; mech_idx < desc->pd_mech_list_count;
8977c478bd9Sstevel@tonic-gate 	    mech_idx++) {
8987c478bd9Sstevel@tonic-gate 		kcf_remove_mech_provider(
8997c478bd9Sstevel@tonic-gate 		    desc->pd_mechanisms[mech_idx].cm_mech_name, desc);
9007c478bd9Sstevel@tonic-gate 	}
9017c478bd9Sstevel@tonic-gate 
9027c478bd9Sstevel@tonic-gate 	/* remove provider from providers table */
9037c478bd9Sstevel@tonic-gate 	if (remove_prov)
9047c478bd9Sstevel@tonic-gate 		(void) kcf_prov_tab_rem_provider(desc->pd_prov_id);
9057c478bd9Sstevel@tonic-gate }
9067c478bd9Sstevel@tonic-gate 
9077c478bd9Sstevel@tonic-gate /*
9087c478bd9Sstevel@tonic-gate  * Utility routine called from crypto_load_soft_disabled(). Callers
9097c478bd9Sstevel@tonic-gate  * should have done a prior undo_register_provider().
9107c478bd9Sstevel@tonic-gate  */
9117c478bd9Sstevel@tonic-gate void
9127c478bd9Sstevel@tonic-gate redo_register_provider(kcf_provider_desc_t *pd)
9137c478bd9Sstevel@tonic-gate {
9147c478bd9Sstevel@tonic-gate 	/* process the mechanisms supported by the provider */
9157c478bd9Sstevel@tonic-gate 	(void) init_prov_mechs(NULL, pd);
9167c478bd9Sstevel@tonic-gate 
9177c478bd9Sstevel@tonic-gate 	/*
9187c478bd9Sstevel@tonic-gate 	 * Hold provider in providers table. We should not call
9197c478bd9Sstevel@tonic-gate 	 * kcf_prov_tab_add_provider() here as the provider descriptor
9207c478bd9Sstevel@tonic-gate 	 * is still valid which means it has an entry in the provider
9217c478bd9Sstevel@tonic-gate 	 * table.
9227c478bd9Sstevel@tonic-gate 	 */
9237c478bd9Sstevel@tonic-gate 	KCF_PROV_REFHOLD(pd);
9247c478bd9Sstevel@tonic-gate }
9257c478bd9Sstevel@tonic-gate 
9267c478bd9Sstevel@tonic-gate /*
9277c478bd9Sstevel@tonic-gate  * Add provider (p1) to another provider's array of providers (p2).
9287c478bd9Sstevel@tonic-gate  * Hardware and logical providers use this array to cross-reference
9297c478bd9Sstevel@tonic-gate  * each other.
9307c478bd9Sstevel@tonic-gate  */
9317c478bd9Sstevel@tonic-gate static void
9327c478bd9Sstevel@tonic-gate add_provider_to_array(kcf_provider_desc_t *p1, kcf_provider_desc_t *p2)
9337c478bd9Sstevel@tonic-gate {
9347c478bd9Sstevel@tonic-gate 	kcf_provider_list_t *new;
9357c478bd9Sstevel@tonic-gate 
9367c478bd9Sstevel@tonic-gate 	new = kmem_alloc(sizeof (kcf_provider_list_t), KM_SLEEP);
9377c478bd9Sstevel@tonic-gate 	mutex_enter(&p2->pd_lock);
9387c478bd9Sstevel@tonic-gate 	new->pl_next = p2->pd_provider_list;
9397c478bd9Sstevel@tonic-gate 	p2->pd_provider_list = new;
9407c478bd9Sstevel@tonic-gate 	new->pl_provider = p1;
9417c478bd9Sstevel@tonic-gate 	mutex_exit(&p2->pd_lock);
9427c478bd9Sstevel@tonic-gate }
9437c478bd9Sstevel@tonic-gate 
9447c478bd9Sstevel@tonic-gate /*
9457c478bd9Sstevel@tonic-gate  * Remove provider (p1) from another provider's array of providers (p2).
9467c478bd9Sstevel@tonic-gate  * Hardware and logical providers use this array to cross-reference
9477c478bd9Sstevel@tonic-gate  * each other.
9487c478bd9Sstevel@tonic-gate  */
9497c478bd9Sstevel@tonic-gate static void
9507c478bd9Sstevel@tonic-gate remove_provider_from_array(kcf_provider_desc_t *p1, kcf_provider_desc_t *p2)
9517c478bd9Sstevel@tonic-gate {
9527c478bd9Sstevel@tonic-gate 
9537c478bd9Sstevel@tonic-gate 	kcf_provider_list_t *pl = NULL, **prev;
9547c478bd9Sstevel@tonic-gate 
9557c478bd9Sstevel@tonic-gate 	mutex_enter(&p2->pd_lock);
9567c478bd9Sstevel@tonic-gate 	for (pl = p2->pd_provider_list, prev = &p2->pd_provider_list;
9577c478bd9Sstevel@tonic-gate 	    pl != NULL; prev = &pl->pl_next, pl = pl->pl_next) {
9587c478bd9Sstevel@tonic-gate 		if (pl->pl_provider == p1) {
9597c478bd9Sstevel@tonic-gate 			break;
9607c478bd9Sstevel@tonic-gate 		}
9617c478bd9Sstevel@tonic-gate 	}
9627c478bd9Sstevel@tonic-gate 
9637c478bd9Sstevel@tonic-gate 	if (p1 == NULL) {
9647c478bd9Sstevel@tonic-gate 		mutex_exit(&p2->pd_lock);
9657c478bd9Sstevel@tonic-gate 		return;
9667c478bd9Sstevel@tonic-gate 	}
9677c478bd9Sstevel@tonic-gate 
9687c478bd9Sstevel@tonic-gate 	/* detach and free kcf_provider_list structure */
9697c478bd9Sstevel@tonic-gate 	*prev = pl->pl_next;
9707c478bd9Sstevel@tonic-gate 	kmem_free(pl, sizeof (*pl));
9717c478bd9Sstevel@tonic-gate 	mutex_exit(&p2->pd_lock);
9727c478bd9Sstevel@tonic-gate }
9737c478bd9Sstevel@tonic-gate 
9747c478bd9Sstevel@tonic-gate /*
9757c478bd9Sstevel@tonic-gate  * Convert an array of logical provider handles (crypto_provider_id)
9767c478bd9Sstevel@tonic-gate  * stored in a crypto_provider_info structure into an array of provider
9777c478bd9Sstevel@tonic-gate  * descriptors (kcf_provider_desc_t) attached to a logical provider.
9787c478bd9Sstevel@tonic-gate  */
9797c478bd9Sstevel@tonic-gate static void
9807c478bd9Sstevel@tonic-gate process_logical_providers(crypto_provider_info_t *info, kcf_provider_desc_t *hp)
9817c478bd9Sstevel@tonic-gate {
9827c478bd9Sstevel@tonic-gate 	kcf_provider_desc_t *lp;
9837c478bd9Sstevel@tonic-gate 	crypto_provider_id_t handle;
9847c478bd9Sstevel@tonic-gate 	int count = info->pi_logical_provider_count;
9857c478bd9Sstevel@tonic-gate 	int i;
9867c478bd9Sstevel@tonic-gate 
9877c478bd9Sstevel@tonic-gate 	/* add hardware provider to each logical provider */
9887c478bd9Sstevel@tonic-gate 	for (i = 0; i < count; i++) {
9897c478bd9Sstevel@tonic-gate 		handle = info->pi_logical_providers[i];
9907c478bd9Sstevel@tonic-gate 		lp = kcf_prov_tab_lookup((crypto_provider_id_t)handle);
9917c478bd9Sstevel@tonic-gate 		if (lp == NULL) {
9927c478bd9Sstevel@tonic-gate 			continue;
9937c478bd9Sstevel@tonic-gate 		}
9947c478bd9Sstevel@tonic-gate 		add_provider_to_array(hp, lp);
995c892ebf1Skrishna 		hp->pd_flags |= KCF_LPROV_MEMBER;
9967c478bd9Sstevel@tonic-gate 
9977c478bd9Sstevel@tonic-gate 		/*
9987c478bd9Sstevel@tonic-gate 		 * A hardware provider has to have the provider descriptor of
9997c478bd9Sstevel@tonic-gate 		 * every logical provider it belongs to, so it can be removed
10007c478bd9Sstevel@tonic-gate 		 * from the logical provider if the hardware provider
10017c478bd9Sstevel@tonic-gate 		 * unregisters from the framework.
10027c478bd9Sstevel@tonic-gate 		 */
10037c478bd9Sstevel@tonic-gate 		add_provider_to_array(lp, hp);
10047c478bd9Sstevel@tonic-gate 		KCF_PROV_REFRELE(lp);
10057c478bd9Sstevel@tonic-gate 	}
10067c478bd9Sstevel@tonic-gate }
10077c478bd9Sstevel@tonic-gate 
10087c478bd9Sstevel@tonic-gate /*
10097c478bd9Sstevel@tonic-gate  * This routine removes a provider from all of the logical or
10107c478bd9Sstevel@tonic-gate  * hardware providers it belongs to, and frees the provider's
10117c478bd9Sstevel@tonic-gate  * array of pointers to providers.
10127c478bd9Sstevel@tonic-gate  */
10137c478bd9Sstevel@tonic-gate static void
10147c478bd9Sstevel@tonic-gate remove_provider(kcf_provider_desc_t *pp)
10157c478bd9Sstevel@tonic-gate {
10167c478bd9Sstevel@tonic-gate 	kcf_provider_desc_t *p;
10177c478bd9Sstevel@tonic-gate 	kcf_provider_list_t *e, *next;
10187c478bd9Sstevel@tonic-gate 
10197c478bd9Sstevel@tonic-gate 	mutex_enter(&pp->pd_lock);
10207c478bd9Sstevel@tonic-gate 	for (e = pp->pd_provider_list; e != NULL; e = next) {
10217c478bd9Sstevel@tonic-gate 		p = e->pl_provider;
10227c478bd9Sstevel@tonic-gate 		remove_provider_from_array(pp, p);
1023c892ebf1Skrishna 		if (p->pd_prov_type == CRYPTO_HW_PROVIDER &&
1024c892ebf1Skrishna 		    p->pd_provider_list == NULL)
1025c892ebf1Skrishna 			p->pd_flags &= ~KCF_LPROV_MEMBER;
10267c478bd9Sstevel@tonic-gate 		next = e->pl_next;
10277c478bd9Sstevel@tonic-gate 		kmem_free(e, sizeof (*e));
10287c478bd9Sstevel@tonic-gate 	}
10297c478bd9Sstevel@tonic-gate 	pp->pd_provider_list = NULL;
10307c478bd9Sstevel@tonic-gate 	mutex_exit(&pp->pd_lock);
10317c478bd9Sstevel@tonic-gate }
1032fe2f7468Skrishna 
1033fe2f7468Skrishna /*
1034fe2f7468Skrishna  * Dispatch events as needed for a provider. is_added flag tells
1035fe2f7468Skrishna  * whether the provider is registering or unregistering.
1036fe2f7468Skrishna  */
1037fe2f7468Skrishna void
1038fe2f7468Skrishna kcf_do_notify(kcf_provider_desc_t *prov_desc, boolean_t is_added)
1039fe2f7468Skrishna {
1040fe2f7468Skrishna 	int i;
1041fe2f7468Skrishna 	crypto_notify_event_change_t ec;
1042fe2f7468Skrishna 
1043fe2f7468Skrishna 	ASSERT(prov_desc->pd_state > KCF_PROV_VERIFICATION_FAILED);
1044fe2f7468Skrishna 
1045fe2f7468Skrishna 	/*
1046fe2f7468Skrishna 	 * Inform interested clients of the mechanisms becoming
1047fe2f7468Skrishna 	 * available/unavailable. We skip this for logical providers
1048fe2f7468Skrishna 	 * as they do not affect mechanisms.
1049fe2f7468Skrishna 	 */
1050fe2f7468Skrishna 	if (prov_desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) {
1051fe2f7468Skrishna 		ec.ec_provider_type = prov_desc->pd_prov_type;
1052fe2f7468Skrishna 		ec.ec_change = is_added ? CRYPTO_MECH_ADDED :
1053fe2f7468Skrishna 		    CRYPTO_MECH_REMOVED;
1054fe2f7468Skrishna 		for (i = 0; i < prov_desc->pd_mech_list_count; i++) {
1055fe2f7468Skrishna 			/* Skip any mechanisms not allowed by the policy */
1056fe2f7468Skrishna 			if (is_mech_disabled(prov_desc,
1057fe2f7468Skrishna 			    prov_desc->pd_mechanisms[i].cm_mech_name))
1058fe2f7468Skrishna 				continue;
1059fe2f7468Skrishna 
1060fe2f7468Skrishna 			(void) strncpy(ec.ec_mech_name,
1061fe2f7468Skrishna 			    prov_desc->pd_mechanisms[i].cm_mech_name,
1062fe2f7468Skrishna 			    CRYPTO_MAX_MECH_NAME);
1063fe2f7468Skrishna 			kcf_walk_ntfylist(CRYPTO_EVENT_MECHS_CHANGED, &ec);
1064fe2f7468Skrishna 		}
1065fe2f7468Skrishna 
1066fe2f7468Skrishna 	}
1067fe2f7468Skrishna 
1068fe2f7468Skrishna 	/*
1069fe2f7468Skrishna 	 * Inform interested clients about the new or departing provider.
1070fe2f7468Skrishna 	 * In case of a logical provider, we need to notify the event only
1071fe2f7468Skrishna 	 * for the logical provider and not for the underlying
1072fe2f7468Skrishna 	 * providers which are known by the KCF_LPROV_MEMBER bit.
1073fe2f7468Skrishna 	 */
1074fe2f7468Skrishna 	if (prov_desc->pd_prov_type == CRYPTO_LOGICAL_PROVIDER ||
1075fe2f7468Skrishna 	    (prov_desc->pd_flags & KCF_LPROV_MEMBER) == 0) {
1076fe2f7468Skrishna 		kcf_walk_ntfylist(is_added ? CRYPTO_EVENT_PROVIDER_REGISTERED :
1077fe2f7468Skrishna 		    CRYPTO_EVENT_PROVIDER_UNREGISTERED, prov_desc);
1078fe2f7468Skrishna 	}
1079fe2f7468Skrishna }
1080fe2f7468Skrishna 
1081fe2f7468Skrishna static void
1082fe2f7468Skrishna delete_kstat(kcf_provider_desc_t *desc)
1083fe2f7468Skrishna {
1084fe2f7468Skrishna 	/* destroy the kstat created for this provider */
1085fe2f7468Skrishna 	if (desc->pd_kstat != NULL) {
1086fe2f7468Skrishna 		kcf_provider_desc_t *kspd = desc->pd_kstat->ks_private;
1087fe2f7468Skrishna 
1088fe2f7468Skrishna 		/* release reference held by desc->pd_kstat->ks_private */
1089fe2f7468Skrishna 		ASSERT(desc == kspd);
1090fe2f7468Skrishna 		kstat_delete(kspd->pd_kstat);
1091fe2f7468Skrishna 		desc->pd_kstat = NULL;
1092fe2f7468Skrishna 		KCF_PROV_REFRELE(kspd);
1093fe2f7468Skrishna 	}
1094fe2f7468Skrishna }
1095