xref: /onnv-gate/usr/src/uts/common/crypto/spi/kcf_spi.c (revision 904:4f885c862682)
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
50Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
60Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
70Sstevel@tonic-gate  * with the License.
80Sstevel@tonic-gate  *
90Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
100Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
110Sstevel@tonic-gate  * See the License for the specific language governing permissions
120Sstevel@tonic-gate  * and limitations under the License.
130Sstevel@tonic-gate  *
140Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
150Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
160Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
170Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
180Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
190Sstevel@tonic-gate  *
200Sstevel@tonic-gate  * CDDL HEADER END
210Sstevel@tonic-gate  */
220Sstevel@tonic-gate /*
230Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
240Sstevel@tonic-gate  * Use is subject to license terms.
250Sstevel@tonic-gate  */
260Sstevel@tonic-gate 
270Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
280Sstevel@tonic-gate 
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate  * This file is part of the core Kernel Cryptographic Framework.
310Sstevel@tonic-gate  * It implements the SPI functions exported to cryptographic
320Sstevel@tonic-gate  * providers.
330Sstevel@tonic-gate  */
340Sstevel@tonic-gate 
350Sstevel@tonic-gate #include <sys/ksynch.h>
360Sstevel@tonic-gate #include <sys/cmn_err.h>
370Sstevel@tonic-gate #include <sys/ddi.h>
380Sstevel@tonic-gate #include <sys/sunddi.h>
390Sstevel@tonic-gate #include <sys/modctl.h>
400Sstevel@tonic-gate #include <sys/crypto/common.h>
410Sstevel@tonic-gate #include <sys/crypto/impl.h>
420Sstevel@tonic-gate #include <sys/crypto/sched_impl.h>
430Sstevel@tonic-gate #include <sys/crypto/spi.h>
440Sstevel@tonic-gate #include <sys/taskq.h>
450Sstevel@tonic-gate #include <sys/disp.h>
460Sstevel@tonic-gate #include <sys/kstat.h>
470Sstevel@tonic-gate #include <sys/policy.h>
480Sstevel@tonic-gate 
490Sstevel@tonic-gate /*
500Sstevel@tonic-gate  * minalloc and maxalloc values to be used for taskq_create().
510Sstevel@tonic-gate  */
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 free_provider_list(kcf_provider_list_t *);
560Sstevel@tonic-gate static void remove_provider(kcf_provider_desc_t *);
570Sstevel@tonic-gate static void process_logical_providers(crypto_provider_info_t *,
580Sstevel@tonic-gate     kcf_provider_desc_t *);
59*904Smcpowers static void copy_ops_vector_v1(crypto_ops_t *, crypto_ops_t *);
60*904Smcpowers static void copy_ops_vector_v2(crypto_ops_t *, crypto_ops_t *);
610Sstevel@tonic-gate static int init_prov_mechs(crypto_provider_info_t *, kcf_provider_desc_t *);
620Sstevel@tonic-gate static int kcf_prov_kstat_update(kstat_t *, int);
630Sstevel@tonic-gate 
640Sstevel@tonic-gate static kcf_prov_stats_t kcf_stats_ks_data_template = {
650Sstevel@tonic-gate 	{ "kcf_ops_total",		KSTAT_DATA_UINT64 },
660Sstevel@tonic-gate 	{ "kcf_ops_passed",		KSTAT_DATA_UINT64 },
670Sstevel@tonic-gate 	{ "kcf_ops_failed",		KSTAT_DATA_UINT64 },
680Sstevel@tonic-gate 	{ "kcf_ops_returned_busy",	KSTAT_DATA_UINT64 }
690Sstevel@tonic-gate };
700Sstevel@tonic-gate 
710Sstevel@tonic-gate #define	KCF_SPI_COPY_OPS(src, dst, ops) if ((src)->ops != NULL) \
720Sstevel@tonic-gate 	*((dst)->ops) = *((src)->ops);
730Sstevel@tonic-gate 
740Sstevel@tonic-gate /*
750Sstevel@tonic-gate  * This routine is used to add cryptographic providers to the KEF framework.
760Sstevel@tonic-gate  * Providers pass a crypto_provider_info structure to crypto_register_provider()
770Sstevel@tonic-gate  * and get back a handle.  The crypto_provider_info structure contains a
780Sstevel@tonic-gate  * list of mechanisms supported by the provider and an ops vector containing
790Sstevel@tonic-gate  * provider entry points.  Hardware providers call this routine in their attach
800Sstevel@tonic-gate  * routines.  Software providers call this routine in their _init() routine.
810Sstevel@tonic-gate  */
820Sstevel@tonic-gate int
830Sstevel@tonic-gate crypto_register_provider(crypto_provider_info_t *info,
840Sstevel@tonic-gate     crypto_kcf_provider_handle_t *handle)
850Sstevel@tonic-gate {
860Sstevel@tonic-gate 	int i;
870Sstevel@tonic-gate 	int vstatus = 0;
880Sstevel@tonic-gate 	struct modctl *mcp;
890Sstevel@tonic-gate 	char *name;
900Sstevel@tonic-gate 	char ks_name[KSTAT_STRLEN];
910Sstevel@tonic-gate 	crypto_notify_event_change_t ec;
920Sstevel@tonic-gate 
930Sstevel@tonic-gate 	kcf_provider_desc_t *prov_desc = NULL;
940Sstevel@tonic-gate 	int ret = CRYPTO_ARGUMENTS_BAD;
950Sstevel@tonic-gate 
96*904Smcpowers 	if (info->pi_interface_version > CRYPTO_SPI_VERSION_2)
970Sstevel@tonic-gate 		return (CRYPTO_VERSION_MISMATCH);
980Sstevel@tonic-gate 
990Sstevel@tonic-gate 	/*
1000Sstevel@tonic-gate 	 * Check provider type, must be software, hardware, or logical.
1010Sstevel@tonic-gate 	 */
1020Sstevel@tonic-gate 	if (info->pi_provider_type != CRYPTO_HW_PROVIDER &&
1030Sstevel@tonic-gate 	    info->pi_provider_type != CRYPTO_SW_PROVIDER &&
1040Sstevel@tonic-gate 	    info->pi_provider_type != CRYPTO_LOGICAL_PROVIDER)
1050Sstevel@tonic-gate 		return (CRYPTO_ARGUMENTS_BAD);
1060Sstevel@tonic-gate 
1070Sstevel@tonic-gate 	/*
1080Sstevel@tonic-gate 	 * Allocate and initialize a new provider descriptor. We also
1090Sstevel@tonic-gate 	 * hold it and release it when done.
1100Sstevel@tonic-gate 	 */
1110Sstevel@tonic-gate 	prov_desc = kcf_alloc_provider_desc(info);
1120Sstevel@tonic-gate 	KCF_PROV_REFHOLD(prov_desc);
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate 	prov_desc->pd_prov_type = info->pi_provider_type;
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate 	/* provider-private handle, opaque to KCF */
1170Sstevel@tonic-gate 	prov_desc->pd_prov_handle = info->pi_provider_handle;
1180Sstevel@tonic-gate 
1190Sstevel@tonic-gate 	/* copy provider description string */
1200Sstevel@tonic-gate 	if (info->pi_provider_description != NULL) {
1210Sstevel@tonic-gate 		/*
1220Sstevel@tonic-gate 		 * pi_provider_descriptor is a string that can contain
1230Sstevel@tonic-gate 		 * up to CRYPTO_PROVIDER_DESCR_MAX_LEN + 1 characters
1240Sstevel@tonic-gate 		 * INCLUDING the terminating null character. A bcopy()
1250Sstevel@tonic-gate 		 * is necessary here as pd_description should not have
1260Sstevel@tonic-gate 		 * a null character. See comments in kcf_alloc_provider_desc()
1270Sstevel@tonic-gate 		 * for details on pd_description field.
1280Sstevel@tonic-gate 		 */
1290Sstevel@tonic-gate 		bcopy(info->pi_provider_description, prov_desc->pd_description,
1300Sstevel@tonic-gate 		    min(strlen(info->pi_provider_description),
1310Sstevel@tonic-gate 		    CRYPTO_PROVIDER_DESCR_MAX_LEN));
1320Sstevel@tonic-gate 	}
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate 	if (info->pi_provider_type != CRYPTO_LOGICAL_PROVIDER) {
1350Sstevel@tonic-gate 		if (info->pi_ops_vector == NULL) {
1360Sstevel@tonic-gate 			return (CRYPTO_ARGUMENTS_BAD);
1370Sstevel@tonic-gate 		}
138*904Smcpowers 		copy_ops_vector_v1(info->pi_ops_vector,
139*904Smcpowers 		    prov_desc->pd_ops_vector);
140*904Smcpowers 		if (info->pi_interface_version == CRYPTO_SPI_VERSION_2) {
141*904Smcpowers 			copy_ops_vector_v2(info->pi_ops_vector,
142*904Smcpowers 			    prov_desc->pd_ops_vector);
143*904Smcpowers 			prov_desc->pd_flags = info->pi_flags;
144*904Smcpowers 		}
1450Sstevel@tonic-gate 	}
1460Sstevel@tonic-gate 
1470Sstevel@tonic-gate 	/*
1480Sstevel@tonic-gate 	 * For software providers, copy the module name and module ID.
1490Sstevel@tonic-gate 	 * For hardware providers, copy the driver name and instance.
1500Sstevel@tonic-gate 	 */
1510Sstevel@tonic-gate 	switch (info->pi_provider_type) {
1520Sstevel@tonic-gate 	case  CRYPTO_SW_PROVIDER:
1530Sstevel@tonic-gate 		if (info->pi_provider_dev.pd_sw == NULL)
1540Sstevel@tonic-gate 			goto bail;
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate 		if ((mcp = mod_getctl(info->pi_provider_dev.pd_sw)) == NULL)
1570Sstevel@tonic-gate 			goto bail;
1580Sstevel@tonic-gate 
1590Sstevel@tonic-gate 		prov_desc->pd_module_id = mcp->mod_id;
1600Sstevel@tonic-gate 		name = mcp->mod_modname;
1610Sstevel@tonic-gate 		break;
1620Sstevel@tonic-gate 
1630Sstevel@tonic-gate 	case CRYPTO_HW_PROVIDER:
1640Sstevel@tonic-gate 	case CRYPTO_LOGICAL_PROVIDER:
1650Sstevel@tonic-gate 		if (info->pi_provider_dev.pd_hw == NULL)
1660Sstevel@tonic-gate 			goto bail;
1670Sstevel@tonic-gate 
1680Sstevel@tonic-gate 		prov_desc->pd_instance =
1690Sstevel@tonic-gate 		    ddi_get_instance(info->pi_provider_dev.pd_hw);
1700Sstevel@tonic-gate 		name = (char *)ddi_driver_name(info->pi_provider_dev.pd_hw);
1710Sstevel@tonic-gate 		break;
1720Sstevel@tonic-gate 	}
1730Sstevel@tonic-gate 	if (name == NULL)
1740Sstevel@tonic-gate 		goto bail;
1750Sstevel@tonic-gate 
1760Sstevel@tonic-gate 	prov_desc->pd_name = kmem_alloc(strlen(name) + 1, KM_SLEEP);
1770Sstevel@tonic-gate 	(void) strcpy(prov_desc->pd_name, name);
1780Sstevel@tonic-gate 
1790Sstevel@tonic-gate 	if ((prov_desc->pd_mctlp = kcf_get_modctl(info)) == NULL)
1800Sstevel@tonic-gate 		goto bail;
1810Sstevel@tonic-gate 
1820Sstevel@tonic-gate 	/* process the mechanisms supported by the provider */
1830Sstevel@tonic-gate 	if ((ret = init_prov_mechs(info, prov_desc)) != CRYPTO_SUCCESS)
1840Sstevel@tonic-gate 		goto bail;
1850Sstevel@tonic-gate 
1860Sstevel@tonic-gate 	/*
1870Sstevel@tonic-gate 	 * Add provider to providers tables, also sets the descriptor
1880Sstevel@tonic-gate 	 * pd_prov_id field.
1890Sstevel@tonic-gate 	 */
1900Sstevel@tonic-gate 	if ((ret = kcf_prov_tab_add_provider(prov_desc)) != CRYPTO_SUCCESS) {
1910Sstevel@tonic-gate 		undo_register_provider(prov_desc, B_FALSE);
1920Sstevel@tonic-gate 		goto bail;
1930Sstevel@tonic-gate 	}
1940Sstevel@tonic-gate 
1950Sstevel@tonic-gate 	if (info->pi_provider_type != CRYPTO_LOGICAL_PROVIDER) {
1960Sstevel@tonic-gate 		if ((vstatus = kcf_verify_signature(prov_desc)) ==
1970Sstevel@tonic-gate 		    CRYPTO_MODVERIFICATION_FAILED) {
1980Sstevel@tonic-gate 			undo_register_provider(prov_desc, B_TRUE);
1990Sstevel@tonic-gate 			ret = CRYPTO_MODVERIFICATION_FAILED;
2000Sstevel@tonic-gate 			goto bail;
2010Sstevel@tonic-gate 		}
2020Sstevel@tonic-gate 	}
2030Sstevel@tonic-gate 
2040Sstevel@tonic-gate 	/*
2050Sstevel@tonic-gate 	 * We create a taskq only for a hardware provider. The global
2060Sstevel@tonic-gate 	 * software queue is used for software providers. The taskq
2070Sstevel@tonic-gate 	 * is limited to one thread since tasks are guaranteed to be
2080Sstevel@tonic-gate 	 * executed in the order they are scheduled, if nthreads == 1. We
2090Sstevel@tonic-gate 	 * pass TASKQ_PREPOPULATE flag to keep some entries cached to
2100Sstevel@tonic-gate 	 * improve performance.
2110Sstevel@tonic-gate 	 */
2120Sstevel@tonic-gate 	if (prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER)
2130Sstevel@tonic-gate 		prov_desc->pd_sched_info.ks_taskq = taskq_create("kcf_taskq",
2140Sstevel@tonic-gate 		    1, minclsyspri, crypto_taskq_minalloc,
2150Sstevel@tonic-gate 		    crypto_taskq_maxalloc, TASKQ_PREPOPULATE);
2160Sstevel@tonic-gate 	else
2170Sstevel@tonic-gate 		prov_desc->pd_sched_info.ks_taskq = NULL;
2180Sstevel@tonic-gate 
2190Sstevel@tonic-gate 	/* no kernel session to logical providers */
2200Sstevel@tonic-gate 	if (prov_desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) {
2210Sstevel@tonic-gate 		/*
2220Sstevel@tonic-gate 		 * Open a session for session-oriented providers. This session
2230Sstevel@tonic-gate 		 * is used for all kernel consumers. This is fine as a provider
2240Sstevel@tonic-gate 		 * is required to support multiple thread access to a session.
2250Sstevel@tonic-gate 		 * We can do this only after the taskq has been created as we
2260Sstevel@tonic-gate 		 * do a kcf_submit_request() to open the session.
2270Sstevel@tonic-gate 		 */
2280Sstevel@tonic-gate 		if (KCF_PROV_SESSION_OPS(prov_desc) != NULL) {
2290Sstevel@tonic-gate 			kcf_req_params_t params;
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate 			KCF_WRAP_SESSION_OPS_PARAMS(&params,
2320Sstevel@tonic-gate 			    KCF_OP_SESSION_OPEN, &prov_desc->pd_sid, 0,
2330Sstevel@tonic-gate 			    CRYPTO_USER, NULL, 0, prov_desc);
2340Sstevel@tonic-gate 			ret = kcf_submit_request(prov_desc, NULL, NULL, &params,
2350Sstevel@tonic-gate 			    B_FALSE);
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate 			if (ret != CRYPTO_SUCCESS) {
2380Sstevel@tonic-gate 				undo_register_provider(prov_desc, B_TRUE);
2390Sstevel@tonic-gate 				ret = CRYPTO_FAILED;
2400Sstevel@tonic-gate 				goto bail;
2410Sstevel@tonic-gate 			}
2420Sstevel@tonic-gate 		}
2430Sstevel@tonic-gate 	}
2440Sstevel@tonic-gate 
2450Sstevel@tonic-gate 	if (prov_desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) {
2460Sstevel@tonic-gate 		/*
2470Sstevel@tonic-gate 		 * Create the kstat for this provider. There is a kstat
2480Sstevel@tonic-gate 		 * installed for each successfully registered provider.
2490Sstevel@tonic-gate 		 * This kstat is deleted, when the provider unregisters.
2500Sstevel@tonic-gate 		 */
2510Sstevel@tonic-gate 		if (prov_desc->pd_prov_type == CRYPTO_SW_PROVIDER) {
2520Sstevel@tonic-gate 			(void) snprintf(ks_name, KSTAT_STRLEN, "%s_%s",
2530Sstevel@tonic-gate 			    prov_desc->pd_name, "provider_stats");
2540Sstevel@tonic-gate 		} else {
2550Sstevel@tonic-gate 			(void) snprintf(ks_name, KSTAT_STRLEN, "%s_%d_%u_%s",
2560Sstevel@tonic-gate 			    prov_desc->pd_name, prov_desc->pd_instance,
2570Sstevel@tonic-gate 			    prov_desc->pd_prov_id, "provider_stats");
2580Sstevel@tonic-gate 		}
2590Sstevel@tonic-gate 
2600Sstevel@tonic-gate 		prov_desc->pd_kstat = kstat_create("kcf", 0, ks_name, "crypto",
2610Sstevel@tonic-gate 		    KSTAT_TYPE_NAMED, sizeof (kcf_prov_stats_t) /
2620Sstevel@tonic-gate 		    sizeof (kstat_named_t), KSTAT_FLAG_VIRTUAL);
2630Sstevel@tonic-gate 
2640Sstevel@tonic-gate 		if (prov_desc->pd_kstat != NULL) {
2650Sstevel@tonic-gate 			bcopy(&kcf_stats_ks_data_template,
2660Sstevel@tonic-gate 			    &prov_desc->pd_ks_data,
2670Sstevel@tonic-gate 			    sizeof (kcf_stats_ks_data_template));
2680Sstevel@tonic-gate 			prov_desc->pd_kstat->ks_data = &prov_desc->pd_ks_data;
2690Sstevel@tonic-gate 			KCF_PROV_REFHOLD(prov_desc);
2700Sstevel@tonic-gate 			KCF_PROV_IREFHOLD(prov_desc);
2710Sstevel@tonic-gate 			prov_desc->pd_kstat->ks_private = prov_desc;
2720Sstevel@tonic-gate 			prov_desc->pd_kstat->ks_update = kcf_prov_kstat_update;
2730Sstevel@tonic-gate 			kstat_install(prov_desc->pd_kstat);
2740Sstevel@tonic-gate 		}
2750Sstevel@tonic-gate 	}
2760Sstevel@tonic-gate 
2770Sstevel@tonic-gate 	if (prov_desc->pd_prov_type == CRYPTO_HW_PROVIDER)
2780Sstevel@tonic-gate 		process_logical_providers(info, prov_desc);
2790Sstevel@tonic-gate 
2800Sstevel@tonic-gate 	/*
2810Sstevel@tonic-gate 	 * Inform interested kernel clients of the event.
2820Sstevel@tonic-gate 	 * Logical providers are not visible to kernel clients.
2830Sstevel@tonic-gate 	 */
2840Sstevel@tonic-gate 	if (prov_desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) {
2850Sstevel@tonic-gate 		ec.ec_provider_type = prov_desc->pd_prov_type;
2860Sstevel@tonic-gate 		ec.ec_change = CRYPTO_EVENT_CHANGE_ADDED;
2870Sstevel@tonic-gate 		for (i = 0; i < prov_desc->pd_mech_list_count; i++) {
2880Sstevel@tonic-gate 			/* Skip any mechanisms not allowed by the policy */
2890Sstevel@tonic-gate 			if (is_mech_disabled(prov_desc,
2900Sstevel@tonic-gate 			    prov_desc->pd_mechanisms[i].cm_mech_name))
2910Sstevel@tonic-gate 				continue;
2920Sstevel@tonic-gate 
2930Sstevel@tonic-gate 			(void) strncpy(ec.ec_mech_name,
2940Sstevel@tonic-gate 			    prov_desc->pd_mechanisms[i].cm_mech_name,
2950Sstevel@tonic-gate 			    CRYPTO_MAX_MECH_NAME);
2960Sstevel@tonic-gate 			kcf_walk_ntfylist(CRYPTO_EVENT_PROVIDERS_CHANGE, &ec);
2970Sstevel@tonic-gate 		}
2980Sstevel@tonic-gate 	}
2990Sstevel@tonic-gate 
3000Sstevel@tonic-gate 	mutex_enter(&prov_desc->pd_lock);
3010Sstevel@tonic-gate 	prov_desc->pd_state = (vstatus == 0) ? KCF_PROV_READY :
3020Sstevel@tonic-gate 	    KCF_PROV_UNVERIFIED;
3030Sstevel@tonic-gate 	mutex_exit(&prov_desc->pd_lock);
3040Sstevel@tonic-gate 
3050Sstevel@tonic-gate 	*handle = prov_desc->pd_kcf_prov_handle;
3060Sstevel@tonic-gate 	KCF_PROV_REFRELE(prov_desc);
3070Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate bail:
3100Sstevel@tonic-gate 	KCF_PROV_REFRELE(prov_desc);
3110Sstevel@tonic-gate 	return (ret);
3120Sstevel@tonic-gate }
3130Sstevel@tonic-gate 
3140Sstevel@tonic-gate /*
3150Sstevel@tonic-gate  * This routine is used to notify the framework when a provider is being
3160Sstevel@tonic-gate  * removed.  Hardware providers call this routine in their detach routines.
3170Sstevel@tonic-gate  * Software providers call this routine in their _fini() routine.
3180Sstevel@tonic-gate  */
3190Sstevel@tonic-gate int
3200Sstevel@tonic-gate crypto_unregister_provider(crypto_kcf_provider_handle_t handle)
3210Sstevel@tonic-gate {
3220Sstevel@tonic-gate 	int i;
3230Sstevel@tonic-gate 	uint_t mech_idx;
3240Sstevel@tonic-gate 	kcf_provider_desc_t *desc;
3250Sstevel@tonic-gate 	crypto_notify_event_change_t ec;
3260Sstevel@tonic-gate 	kcf_prov_state_t saved_state;
3270Sstevel@tonic-gate 
3280Sstevel@tonic-gate 	/* lookup provider descriptor */
3290Sstevel@tonic-gate 	if ((desc = kcf_prov_tab_lookup((crypto_provider_id_t)handle)) == NULL)
3300Sstevel@tonic-gate 		return (CRYPTO_UNKNOWN_PROVIDER);
3310Sstevel@tonic-gate 
3320Sstevel@tonic-gate 	mutex_enter(&desc->pd_lock);
3330Sstevel@tonic-gate 	/*
3340Sstevel@tonic-gate 	 * Check if any other thread is disabling or removing
3350Sstevel@tonic-gate 	 * this provider. We return if this is the case.
3360Sstevel@tonic-gate 	 */
3370Sstevel@tonic-gate 	if (desc->pd_state >= KCF_PROV_DISABLED) {
3380Sstevel@tonic-gate 		mutex_exit(&desc->pd_lock);
3390Sstevel@tonic-gate 		/* Release reference held by kcf_prov_tab_lookup(). */
3400Sstevel@tonic-gate 		KCF_PROV_REFRELE(desc);
3410Sstevel@tonic-gate 		return (CRYPTO_BUSY);
3420Sstevel@tonic-gate 	}
3430Sstevel@tonic-gate 
3440Sstevel@tonic-gate 	saved_state = desc->pd_state;
3450Sstevel@tonic-gate 	desc->pd_state = KCF_PROV_REMOVED;
3460Sstevel@tonic-gate 
3470Sstevel@tonic-gate 	if (saved_state == KCF_PROV_BUSY) {
3480Sstevel@tonic-gate 		/*
3490Sstevel@tonic-gate 		 * The per-provider taskq thread may be waiting. We
3500Sstevel@tonic-gate 		 * signal it so that it can start failing requests.
3510Sstevel@tonic-gate 		 * Note that we do not need a cv_broadcast() as we keep
3520Sstevel@tonic-gate 		 * only a single thread per taskq.
3530Sstevel@tonic-gate 		 */
3540Sstevel@tonic-gate 		cv_signal(&desc->pd_resume_cv);
3550Sstevel@tonic-gate 	}
3560Sstevel@tonic-gate 
3570Sstevel@tonic-gate 	if (desc->pd_prov_type == CRYPTO_SW_PROVIDER) {
3580Sstevel@tonic-gate 		/*
3590Sstevel@tonic-gate 		 * Check if this provider is currently being used.
3600Sstevel@tonic-gate 		 * pd_irefcnt is the number of holds from the internal
3610Sstevel@tonic-gate 		 * structures. We add one to account for the above lookup.
3620Sstevel@tonic-gate 		 */
3630Sstevel@tonic-gate 		if (desc->pd_refcnt > desc->pd_irefcnt + 1) {
3640Sstevel@tonic-gate 			desc->pd_state = saved_state;
3650Sstevel@tonic-gate 			mutex_exit(&desc->pd_lock);
3660Sstevel@tonic-gate 			/* Release reference held by kcf_prov_tab_lookup(). */
3670Sstevel@tonic-gate 			KCF_PROV_REFRELE(desc);
3680Sstevel@tonic-gate 			/*
3690Sstevel@tonic-gate 			 * The administrator presumably will stop the clients
3700Sstevel@tonic-gate 			 * thus removing the holds, when they get the busy
3710Sstevel@tonic-gate 			 * return value.  Any retry will succeed then.
3720Sstevel@tonic-gate 			 */
3730Sstevel@tonic-gate 			return (CRYPTO_BUSY);
3740Sstevel@tonic-gate 		}
3750Sstevel@tonic-gate 	}
3760Sstevel@tonic-gate 	mutex_exit(&desc->pd_lock);
3770Sstevel@tonic-gate 
3780Sstevel@tonic-gate 	if (desc->pd_prov_type != CRYPTO_SW_PROVIDER) {
3790Sstevel@tonic-gate 		remove_provider(desc);
3800Sstevel@tonic-gate 	}
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate 	if (desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) {
3830Sstevel@tonic-gate 		/* remove the provider from the mechanisms tables */
3840Sstevel@tonic-gate 		for (mech_idx = 0; mech_idx < desc->pd_mech_list_count;
3850Sstevel@tonic-gate 		    mech_idx++) {
3860Sstevel@tonic-gate 			kcf_remove_mech_provider(
3870Sstevel@tonic-gate 			    desc->pd_mechanisms[mech_idx].cm_mech_name, desc);
3880Sstevel@tonic-gate 		}
3890Sstevel@tonic-gate 	}
3900Sstevel@tonic-gate 
3910Sstevel@tonic-gate 	/* remove provider from providers table */
3920Sstevel@tonic-gate 	if (kcf_prov_tab_rem_provider((crypto_provider_id_t)handle) !=
3930Sstevel@tonic-gate 	    CRYPTO_SUCCESS) {
3940Sstevel@tonic-gate 		/* Release reference held by kcf_prov_tab_lookup(). */
3950Sstevel@tonic-gate 		KCF_PROV_REFRELE(desc);
3960Sstevel@tonic-gate 		return (CRYPTO_UNKNOWN_PROVIDER);
3970Sstevel@tonic-gate 	}
3980Sstevel@tonic-gate 
3990Sstevel@tonic-gate 	/* destroy the kstat created for this provider */
4000Sstevel@tonic-gate 	if (desc->pd_kstat != NULL) {
4010Sstevel@tonic-gate 		kcf_provider_desc_t *kspd = desc->pd_kstat->ks_private;
4020Sstevel@tonic-gate 
4030Sstevel@tonic-gate 		/* release reference held by desc->pd_kstat->ks_private */
4040Sstevel@tonic-gate 		ASSERT(desc == kspd);
4050Sstevel@tonic-gate 		kstat_delete(kspd->pd_kstat);
4060Sstevel@tonic-gate 		KCF_PROV_REFRELE(kspd);
4070Sstevel@tonic-gate 		KCF_PROV_IREFRELE(kspd);
4080Sstevel@tonic-gate 	}
4090Sstevel@tonic-gate 
4100Sstevel@tonic-gate 	if (desc->pd_prov_type == CRYPTO_SW_PROVIDER) {
4110Sstevel@tonic-gate 		/* Release reference held by kcf_prov_tab_lookup(). */
4120Sstevel@tonic-gate 		KCF_PROV_REFRELE(desc);
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 		/*
4150Sstevel@tonic-gate 		 * Wait till the existing requests complete.
4160Sstevel@tonic-gate 		 */
4170Sstevel@tonic-gate 		mutex_enter(&desc->pd_lock);
4180Sstevel@tonic-gate 		while (desc->pd_state != KCF_PROV_FREED)
4190Sstevel@tonic-gate 			cv_wait(&desc->pd_remove_cv, &desc->pd_lock);
4200Sstevel@tonic-gate 		mutex_exit(&desc->pd_lock);
4210Sstevel@tonic-gate 	} else {
4220Sstevel@tonic-gate 		/*
4230Sstevel@tonic-gate 		 * Wait until requests that have been sent to the provider
4240Sstevel@tonic-gate 		 * complete.
4250Sstevel@tonic-gate 		 */
4260Sstevel@tonic-gate 		mutex_enter(&desc->pd_lock);
4270Sstevel@tonic-gate 		while (desc->pd_irefcnt > 0)
4280Sstevel@tonic-gate 			cv_wait(&desc->pd_remove_cv, &desc->pd_lock);
4290Sstevel@tonic-gate 		mutex_exit(&desc->pd_lock);
4300Sstevel@tonic-gate 	}
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate 	/*
4330Sstevel@tonic-gate 	 * Inform interested kernel clients of the event.
4340Sstevel@tonic-gate 	 * Logical providers are not visible to kernel clients.
4350Sstevel@tonic-gate 	 */
4360Sstevel@tonic-gate 	if (desc->pd_prov_type != CRYPTO_LOGICAL_PROVIDER) {
4370Sstevel@tonic-gate 		ec.ec_provider_type = desc->pd_prov_type;
4380Sstevel@tonic-gate 		ec.ec_change = CRYPTO_EVENT_CHANGE_REMOVED;
4390Sstevel@tonic-gate 		for (i = 0; i < desc->pd_mech_list_count; i++) {
4400Sstevel@tonic-gate 			/* Skip any mechanisms not allowed by the policy */
4410Sstevel@tonic-gate 			if (is_mech_disabled(desc,
4420Sstevel@tonic-gate 			    desc->pd_mechanisms[i].cm_mech_name))
4430Sstevel@tonic-gate 				continue;
4440Sstevel@tonic-gate 
4450Sstevel@tonic-gate 			(void) strncpy(ec.ec_mech_name,
4460Sstevel@tonic-gate 			    desc->pd_mechanisms[i].cm_mech_name,
4470Sstevel@tonic-gate 			    CRYPTO_MAX_MECH_NAME);
4480Sstevel@tonic-gate 			kcf_walk_ntfylist(CRYPTO_EVENT_PROVIDERS_CHANGE, &ec);
4490Sstevel@tonic-gate 		}
4500Sstevel@tonic-gate 	}
4510Sstevel@tonic-gate 
4520Sstevel@tonic-gate 	if (desc->pd_prov_type == CRYPTO_SW_PROVIDER) {
4530Sstevel@tonic-gate 		/*
4540Sstevel@tonic-gate 		 * This is the only place where kcf_free_provider_desc()
4550Sstevel@tonic-gate 		 * is called directly. KCF_PROV_REFRELE() should free the
4560Sstevel@tonic-gate 		 * structure in all other places.
4570Sstevel@tonic-gate 		 */
4580Sstevel@tonic-gate 		ASSERT(desc->pd_state == KCF_PROV_FREED &&
4590Sstevel@tonic-gate 		    desc->pd_refcnt == 0);
4600Sstevel@tonic-gate 		kcf_free_provider_desc(desc);
4610Sstevel@tonic-gate 	} else {
4620Sstevel@tonic-gate 		KCF_PROV_REFRELE(desc);
4630Sstevel@tonic-gate 	}
4640Sstevel@tonic-gate 
4650Sstevel@tonic-gate 	return (CRYPTO_SUCCESS);
4660Sstevel@tonic-gate }
4670Sstevel@tonic-gate 
4680Sstevel@tonic-gate /*
4690Sstevel@tonic-gate  * This routine is used to notify the framework that the state of
4700Sstevel@tonic-gate  * a cryptographic provider has changed. Valid state codes are:
4710Sstevel@tonic-gate  *
4720Sstevel@tonic-gate  * CRYPTO_PROVIDER_READY
4730Sstevel@tonic-gate  * 	The provider indicates that it can process more requests. A provider
4740Sstevel@tonic-gate  *	will notify with this event if it previously has notified us with a
4750Sstevel@tonic-gate  *	CRYPTO_PROVIDER_BUSY.
4760Sstevel@tonic-gate  *
4770Sstevel@tonic-gate  * CRYPTO_PROVIDER_BUSY
4780Sstevel@tonic-gate  * 	The provider can not take more requests.
4790Sstevel@tonic-gate  *
4800Sstevel@tonic-gate  * CRYPTO_PROVIDER_FAILED
4810Sstevel@tonic-gate  *	The provider encountered an internal error. The framework will not
4820Sstevel@tonic-gate  * 	be sending any more requests to the provider. The provider may notify
4830Sstevel@tonic-gate  *	with a CRYPTO_PROVIDER_READY, if it is able to recover from the error.
4840Sstevel@tonic-gate  *
4850Sstevel@tonic-gate  * This routine can be called from user or interrupt context.
4860Sstevel@tonic-gate  */
4870Sstevel@tonic-gate void
4880Sstevel@tonic-gate crypto_provider_notification(crypto_kcf_provider_handle_t handle, uint_t state)
4890Sstevel@tonic-gate {
4900Sstevel@tonic-gate 	kcf_provider_desc_t *pd;
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate 	/* lookup the provider from the given handle */
4930Sstevel@tonic-gate 	if ((pd = kcf_prov_tab_lookup((crypto_provider_id_t)handle)) == NULL)
4940Sstevel@tonic-gate 		return;
4950Sstevel@tonic-gate 
4960Sstevel@tonic-gate 	mutex_enter(&pd->pd_lock);
4970Sstevel@tonic-gate 
4980Sstevel@tonic-gate 	if (pd->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
4990Sstevel@tonic-gate 		cmn_err(CE_WARN, "crypto_provider_notification: "
5000Sstevel@tonic-gate 		    "logical provider (%x) ignored\n", handle);
5010Sstevel@tonic-gate 		goto out;
5020Sstevel@tonic-gate 	}
5030Sstevel@tonic-gate 	switch (state) {
5040Sstevel@tonic-gate 	case CRYPTO_PROVIDER_READY:
5050Sstevel@tonic-gate 		switch (pd->pd_state) {
5060Sstevel@tonic-gate 		case KCF_PROV_BUSY:
5070Sstevel@tonic-gate 			pd->pd_state = KCF_PROV_READY;
5080Sstevel@tonic-gate 			/*
5090Sstevel@tonic-gate 			 * Signal the per-provider taskq thread that it
5100Sstevel@tonic-gate 			 * can start submitting requests. Note that we do
5110Sstevel@tonic-gate 			 * not need a cv_broadcast() as we keep only a
5120Sstevel@tonic-gate 			 * single thread per taskq.
5130Sstevel@tonic-gate 			 */
5140Sstevel@tonic-gate 			cv_signal(&pd->pd_resume_cv);
5150Sstevel@tonic-gate 			break;
5160Sstevel@tonic-gate 
5170Sstevel@tonic-gate 		case KCF_PROV_FAILED:
5180Sstevel@tonic-gate 			/*
5190Sstevel@tonic-gate 			 * The provider recovered from the error. Let us
5200Sstevel@tonic-gate 			 * use it now.
5210Sstevel@tonic-gate 			 */
5220Sstevel@tonic-gate 			pd->pd_state = KCF_PROV_READY;
5230Sstevel@tonic-gate 			break;
5240Sstevel@tonic-gate 		}
5250Sstevel@tonic-gate 		break;
5260Sstevel@tonic-gate 
5270Sstevel@tonic-gate 	case CRYPTO_PROVIDER_BUSY:
5280Sstevel@tonic-gate 		switch (pd->pd_state) {
5290Sstevel@tonic-gate 		case KCF_PROV_READY:
5300Sstevel@tonic-gate 			pd->pd_state = KCF_PROV_BUSY;
5310Sstevel@tonic-gate 			break;
5320Sstevel@tonic-gate 		}
5330Sstevel@tonic-gate 		break;
5340Sstevel@tonic-gate 
5350Sstevel@tonic-gate 	case CRYPTO_PROVIDER_FAILED:
5360Sstevel@tonic-gate 		/*
5370Sstevel@tonic-gate 		 * We note the failure and return. The per-provider taskq
5380Sstevel@tonic-gate 		 * thread checks this flag and starts failing the
5390Sstevel@tonic-gate 		 * requests, if it is set. See process_req_hwp() for details.
5400Sstevel@tonic-gate 		 */
5410Sstevel@tonic-gate 		switch (pd->pd_state) {
5420Sstevel@tonic-gate 		case KCF_PROV_READY:
5430Sstevel@tonic-gate 			pd->pd_state = KCF_PROV_FAILED;
5440Sstevel@tonic-gate 			break;
5450Sstevel@tonic-gate 
5460Sstevel@tonic-gate 		case KCF_PROV_BUSY:
5470Sstevel@tonic-gate 			pd->pd_state = KCF_PROV_FAILED;
5480Sstevel@tonic-gate 			/*
5490Sstevel@tonic-gate 			 * The per-provider taskq thread may be waiting. We
5500Sstevel@tonic-gate 			 * signal it so that it can start failing requests.
5510Sstevel@tonic-gate 			 */
5520Sstevel@tonic-gate 			cv_signal(&pd->pd_resume_cv);
5530Sstevel@tonic-gate 			break;
5540Sstevel@tonic-gate 		}
5550Sstevel@tonic-gate 		break;
5560Sstevel@tonic-gate 	}
5570Sstevel@tonic-gate out:
5580Sstevel@tonic-gate 	mutex_exit(&pd->pd_lock);
5590Sstevel@tonic-gate 	KCF_PROV_REFRELE(pd);
5600Sstevel@tonic-gate }
5610Sstevel@tonic-gate 
5620Sstevel@tonic-gate /*
5630Sstevel@tonic-gate  * This routine is used to notify the framework the result of
5640Sstevel@tonic-gate  * an asynchronous request handled by a provider. Valid error
5650Sstevel@tonic-gate  * codes are the same as the CRYPTO_* errors defined in common.h.
5660Sstevel@tonic-gate  *
5670Sstevel@tonic-gate  * This routine can be called from user or interrupt context.
5680Sstevel@tonic-gate  */
5690Sstevel@tonic-gate void
5700Sstevel@tonic-gate crypto_op_notification(crypto_req_handle_t handle, int error)
5710Sstevel@tonic-gate {
5720Sstevel@tonic-gate 	kcf_call_type_t ctype;
5730Sstevel@tonic-gate 
5740Sstevel@tonic-gate 	if ((ctype = GET_REQ_TYPE(handle)) == CRYPTO_SYNCH) {
5750Sstevel@tonic-gate 		kcf_sreq_node_t *sreq = (kcf_sreq_node_t *)handle;
5760Sstevel@tonic-gate 
5770Sstevel@tonic-gate 		if (error != CRYPTO_SUCCESS)
5780Sstevel@tonic-gate 			sreq->sn_provider->pd_sched_info.ks_nfails++;
5790Sstevel@tonic-gate 		KCF_PROV_IREFRELE(sreq->sn_provider);
5800Sstevel@tonic-gate 		kcf_sop_done(sreq, error);
5810Sstevel@tonic-gate 	} else {
5820Sstevel@tonic-gate 		kcf_areq_node_t *areq = (kcf_areq_node_t *)handle;
5830Sstevel@tonic-gate 
5840Sstevel@tonic-gate 		ASSERT(ctype == CRYPTO_ASYNCH);
5850Sstevel@tonic-gate 		if (error != CRYPTO_SUCCESS)
5860Sstevel@tonic-gate 			areq->an_provider->pd_sched_info.ks_nfails++;
5870Sstevel@tonic-gate 		KCF_PROV_IREFRELE(areq->an_provider);
5880Sstevel@tonic-gate 		kcf_aop_done(areq, error);
5890Sstevel@tonic-gate 	}
5900Sstevel@tonic-gate }
5910Sstevel@tonic-gate 
5920Sstevel@tonic-gate /*
5930Sstevel@tonic-gate  * This routine is used by software providers to determine
5940Sstevel@tonic-gate  * whether to use KM_SLEEP or KM_NOSLEEP during memory allocation.
5950Sstevel@tonic-gate  * Note that hardware providers can always use KM_SLEEP. So,
5960Sstevel@tonic-gate  * they do not need to call this routine.
5970Sstevel@tonic-gate  *
5980Sstevel@tonic-gate  * This routine can be called from user or interrupt context.
5990Sstevel@tonic-gate  */
6000Sstevel@tonic-gate int
6010Sstevel@tonic-gate crypto_kmflag(crypto_req_handle_t handle)
6020Sstevel@tonic-gate {
6030Sstevel@tonic-gate 	return (REQHNDL2_KMFLAG(handle));
6040Sstevel@tonic-gate }
6050Sstevel@tonic-gate 
6060Sstevel@tonic-gate 
6070Sstevel@tonic-gate /*
6080Sstevel@tonic-gate  * Copy an ops vector from src to dst. Used during provider registration
6090Sstevel@tonic-gate  * to copy the ops vector from the provider info structure to the
6100Sstevel@tonic-gate  * provider descriptor maintained by KCF.
6110Sstevel@tonic-gate  * Copying the ops vector specified by the provider is needed since the
6120Sstevel@tonic-gate  * framework does not require the provider info structure to be
6130Sstevel@tonic-gate  * persistent.
6140Sstevel@tonic-gate  */
6150Sstevel@tonic-gate static void
616*904Smcpowers copy_ops_vector_v1(crypto_ops_t *src_ops, crypto_ops_t *dst_ops)
6170Sstevel@tonic-gate {
618*904Smcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_control_ops);
619*904Smcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_digest_ops);
620*904Smcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_cipher_ops);
621*904Smcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_mac_ops);
622*904Smcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_sign_ops);
623*904Smcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_verify_ops);
624*904Smcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_dual_ops);
625*904Smcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_dual_cipher_mac_ops);
626*904Smcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_random_ops);
627*904Smcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_session_ops);
628*904Smcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_object_ops);
629*904Smcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_key_ops);
630*904Smcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_provider_ops);
631*904Smcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_ctx_ops);
632*904Smcpowers }
633*904Smcpowers 
634*904Smcpowers static void
635*904Smcpowers copy_ops_vector_v2(crypto_ops_t *src_ops, crypto_ops_t *dst_ops)
636*904Smcpowers {
637*904Smcpowers 	KCF_SPI_COPY_OPS(src_ops, dst_ops, co_mech_ops);
6380Sstevel@tonic-gate }
6390Sstevel@tonic-gate 
6400Sstevel@tonic-gate /*
6410Sstevel@tonic-gate  * Process the mechanism info structures specified by the provider
6420Sstevel@tonic-gate  * during registration. A NULL crypto_provider_info_t indicates
6430Sstevel@tonic-gate  * an already initialized provider descriptor.
6440Sstevel@tonic-gate  *
6450Sstevel@tonic-gate  * Mechanisms are not added to the kernel's mechanism table if the
6460Sstevel@tonic-gate  * provider is a logical provider.
6470Sstevel@tonic-gate  *
6480Sstevel@tonic-gate  * Returns CRYPTO_SUCCESS on success, CRYPTO_ARGUMENTS if one
6490Sstevel@tonic-gate  * of the specified mechanisms was malformed, or CRYPTO_HOST_MEMORY
6500Sstevel@tonic-gate  * if the table of mechanisms is full.
6510Sstevel@tonic-gate  */
6520Sstevel@tonic-gate static int
6530Sstevel@tonic-gate init_prov_mechs(crypto_provider_info_t *info, kcf_provider_desc_t *desc)
6540Sstevel@tonic-gate {
6550Sstevel@tonic-gate 	uint_t mech_idx;
6560Sstevel@tonic-gate 	uint_t cleanup_idx;
6570Sstevel@tonic-gate 	int err = CRYPTO_SUCCESS;
6580Sstevel@tonic-gate 	kcf_prov_mech_desc_t *pmd;
6590Sstevel@tonic-gate 	int desc_use_count = 0;
6600Sstevel@tonic-gate 	int mcount = desc->pd_mech_list_count;
6610Sstevel@tonic-gate 
6620Sstevel@tonic-gate 	if (desc->pd_prov_type == CRYPTO_LOGICAL_PROVIDER) {
6630Sstevel@tonic-gate 		if (info != NULL) {
6640Sstevel@tonic-gate 			ASSERT(info->pi_mechanisms != NULL);
6650Sstevel@tonic-gate 			bcopy(info->pi_mechanisms, desc->pd_mechanisms,
6660Sstevel@tonic-gate 			    sizeof (crypto_mech_info_t) * mcount);
6670Sstevel@tonic-gate 		}
6680Sstevel@tonic-gate 		return (CRYPTO_SUCCESS);
6690Sstevel@tonic-gate 	}
6700Sstevel@tonic-gate 
6710Sstevel@tonic-gate 	/*
6720Sstevel@tonic-gate 	 * Copy the mechanism list from the provider info to the provider
6730Sstevel@tonic-gate 	 * descriptor. desc->pd_mechanisms has an extra crypto_mech_info_t
6740Sstevel@tonic-gate 	 * element if the provider has random_ops since we keep an internal
6750Sstevel@tonic-gate 	 * mechanism, SUN_RANDOM, in this case.
6760Sstevel@tonic-gate 	 */
6770Sstevel@tonic-gate 	if (info != NULL) {
678*904Smcpowers 		if (info->pi_ops_vector->co_random_ops != NULL) {
6790Sstevel@tonic-gate 			crypto_mech_info_t *rand_mi;
6800Sstevel@tonic-gate 
6810Sstevel@tonic-gate 			/*
6820Sstevel@tonic-gate 			 * Need the following check as it is possible to have
6830Sstevel@tonic-gate 			 * a provider that implements just random_ops and has
6840Sstevel@tonic-gate 			 * pi_mechanisms == NULL.
6850Sstevel@tonic-gate 			 */
6860Sstevel@tonic-gate 			if (info->pi_mechanisms != NULL) {
6870Sstevel@tonic-gate 				bcopy(info->pi_mechanisms, desc->pd_mechanisms,
6880Sstevel@tonic-gate 				    sizeof (crypto_mech_info_t) * (mcount - 1));
6890Sstevel@tonic-gate 			}
6900Sstevel@tonic-gate 			rand_mi = &desc->pd_mechanisms[mcount - 1];
6910Sstevel@tonic-gate 
6920Sstevel@tonic-gate 			bzero(rand_mi, sizeof (crypto_mech_info_t));
6930Sstevel@tonic-gate 			(void) strncpy(rand_mi->cm_mech_name, SUN_RANDOM,
6940Sstevel@tonic-gate 			    CRYPTO_MAX_MECH_NAME);
6950Sstevel@tonic-gate 			rand_mi->cm_func_group_mask = CRYPTO_FG_RANDOM;
6960Sstevel@tonic-gate 			/*
6970Sstevel@tonic-gate 			 * What we really need here is a
6980Sstevel@tonic-gate 			 * CRYPTO_KEYSIZE_NOT_APPLICABLE. We make do with the
6990Sstevel@tonic-gate 			 * following for now.
7000Sstevel@tonic-gate 			 */
7010Sstevel@tonic-gate 			rand_mi->cm_keysize_unit = CRYPTO_KEYSIZE_UNIT_IN_BITS;
7020Sstevel@tonic-gate 		} else {
7030Sstevel@tonic-gate 			ASSERT(info->pi_mechanisms != NULL);
7040Sstevel@tonic-gate 			bcopy(info->pi_mechanisms, desc->pd_mechanisms,
7050Sstevel@tonic-gate 			    sizeof (crypto_mech_info_t) * mcount);
7060Sstevel@tonic-gate 		}
7070Sstevel@tonic-gate 	}
7080Sstevel@tonic-gate 
7090Sstevel@tonic-gate 	/*
7100Sstevel@tonic-gate 	 * For each mechanism support by the provider, add the provider
7110Sstevel@tonic-gate 	 * to the corresponding KCF mechanism mech_entry chain.
7120Sstevel@tonic-gate 	 */
7130Sstevel@tonic-gate 	for (mech_idx = 0; mech_idx < desc->pd_mech_list_count; mech_idx++) {
7140Sstevel@tonic-gate 		crypto_mech_info_t *mi = &desc->pd_mechanisms[mech_idx];
7150Sstevel@tonic-gate 
7160Sstevel@tonic-gate 		if (mi->cm_keysize_unit != CRYPTO_KEYSIZE_UNIT_IN_BITS &&
7170Sstevel@tonic-gate 		    mi->cm_keysize_unit != CRYPTO_KEYSIZE_UNIT_IN_BYTES) {
7180Sstevel@tonic-gate 			err = CRYPTO_ARGUMENTS_BAD;
7190Sstevel@tonic-gate 			break;
7200Sstevel@tonic-gate 		}
7210Sstevel@tonic-gate 
7220Sstevel@tonic-gate 		if (kcf_add_mech_provider(mi, desc, &pmd) != KCF_SUCCESS)
7230Sstevel@tonic-gate 			break;
7240Sstevel@tonic-gate 
7250Sstevel@tonic-gate 		if (pmd == NULL)
7260Sstevel@tonic-gate 			continue;
7270Sstevel@tonic-gate 
7280Sstevel@tonic-gate 		/* The provider will be used for this mechanism */
7290Sstevel@tonic-gate 		desc_use_count++;
7300Sstevel@tonic-gate 	}
7310Sstevel@tonic-gate 
7320Sstevel@tonic-gate 	/*
7330Sstevel@tonic-gate 	 * The provider will not be used for any mechanism. So, we fail its
7340Sstevel@tonic-gate 	 * registration. Note that if at least one of the mechanisms from the
7350Sstevel@tonic-gate 	 * provider can be used, we do it. This means there can be a overlap
7360Sstevel@tonic-gate 	 * between the mechanisms offered by providers. The first one to
7370Sstevel@tonic-gate 	 * register is used. Also, a policy to disable mechanisms of a provider
7380Sstevel@tonic-gate 	 * will cause the provider to be not used for those mechanisms.
7390Sstevel@tonic-gate 	 */
7400Sstevel@tonic-gate 	if (desc_use_count == 0)
7410Sstevel@tonic-gate 		return (CRYPTO_ARGUMENTS_BAD);
7420Sstevel@tonic-gate 
7430Sstevel@tonic-gate 	if (err == KCF_SUCCESS)
7440Sstevel@tonic-gate 		return (CRYPTO_SUCCESS);
7450Sstevel@tonic-gate 
7460Sstevel@tonic-gate 	/*
7470Sstevel@tonic-gate 	 * An error occurred while adding the mechanism, cleanup
7480Sstevel@tonic-gate 	 * and bail.
7490Sstevel@tonic-gate 	 */
7500Sstevel@tonic-gate 	for (cleanup_idx = 0; cleanup_idx < mech_idx; cleanup_idx++) {
7510Sstevel@tonic-gate 		kcf_remove_mech_provider(
7520Sstevel@tonic-gate 		    desc->pd_mechanisms[cleanup_idx].cm_mech_name, desc);
7530Sstevel@tonic-gate 	}
7540Sstevel@tonic-gate 
7550Sstevel@tonic-gate 	if (err == KCF_MECH_TAB_FULL)
7560Sstevel@tonic-gate 		return (CRYPTO_HOST_MEMORY);
7570Sstevel@tonic-gate 
7580Sstevel@tonic-gate 	return (CRYPTO_ARGUMENTS_BAD);
7590Sstevel@tonic-gate }
7600Sstevel@tonic-gate 
7610Sstevel@tonic-gate /*
7620Sstevel@tonic-gate  * Update routine for kstat. Only privileged users are allowed to
7630Sstevel@tonic-gate  * access this information, since this information is sensitive.
7640Sstevel@tonic-gate  * There are some cryptographic attacks (e.g. traffic analysis)
7650Sstevel@tonic-gate  * which can use this information.
7660Sstevel@tonic-gate  */
7670Sstevel@tonic-gate static int
7680Sstevel@tonic-gate kcf_prov_kstat_update(kstat_t *ksp, int rw)
7690Sstevel@tonic-gate {
7700Sstevel@tonic-gate 	kcf_prov_stats_t *ks_data;
7710Sstevel@tonic-gate 	kcf_provider_desc_t *pd = (kcf_provider_desc_t *)ksp->ks_private;
7720Sstevel@tonic-gate 
7730Sstevel@tonic-gate 	if (rw == KSTAT_WRITE)
7740Sstevel@tonic-gate 		return (EACCES);
7750Sstevel@tonic-gate 
7760Sstevel@tonic-gate 	ks_data = ksp->ks_data;
7770Sstevel@tonic-gate 
7780Sstevel@tonic-gate 	if (secpolicy_sys_config(CRED(), B_TRUE) != 0) {
7790Sstevel@tonic-gate 		ks_data->ps_ops_total.value.ui64 = 0;
7800Sstevel@tonic-gate 		ks_data->ps_ops_passed.value.ui64 = 0;
7810Sstevel@tonic-gate 		ks_data->ps_ops_failed.value.ui64 = 0;
7820Sstevel@tonic-gate 		ks_data->ps_ops_busy_rval.value.ui64 = 0;
7830Sstevel@tonic-gate 	} else {
7840Sstevel@tonic-gate 		ks_data->ps_ops_total.value.ui64 =
7850Sstevel@tonic-gate 		    pd->pd_sched_info.ks_ndispatches;
7860Sstevel@tonic-gate 		ks_data->ps_ops_failed.value.ui64 =
7870Sstevel@tonic-gate 		    pd->pd_sched_info.ks_nfails;
7880Sstevel@tonic-gate 		ks_data->ps_ops_busy_rval.value.ui64 =
7890Sstevel@tonic-gate 		    pd->pd_sched_info.ks_nbusy_rval;
7900Sstevel@tonic-gate 		ks_data->ps_ops_passed.value.ui64 =
7910Sstevel@tonic-gate 		    pd->pd_sched_info.ks_ndispatches -
7920Sstevel@tonic-gate 		    pd->pd_sched_info.ks_nfails -
7930Sstevel@tonic-gate 		    pd->pd_sched_info.ks_nbusy_rval;
7940Sstevel@tonic-gate 	}
7950Sstevel@tonic-gate 
7960Sstevel@tonic-gate 	return (0);
7970Sstevel@tonic-gate }
7980Sstevel@tonic-gate 
7990Sstevel@tonic-gate 
8000Sstevel@tonic-gate /*
8010Sstevel@tonic-gate  * Utility routine called from failure paths in crypto_register_provider()
8020Sstevel@tonic-gate  * and from crypto_load_soft_disabled().
8030Sstevel@tonic-gate  */
8040Sstevel@tonic-gate void
8050Sstevel@tonic-gate undo_register_provider(kcf_provider_desc_t *desc, boolean_t remove_prov)
8060Sstevel@tonic-gate {
8070Sstevel@tonic-gate 	uint_t mech_idx;
8080Sstevel@tonic-gate 
8090Sstevel@tonic-gate 	/* remove the provider from the mechanisms tables */
8100Sstevel@tonic-gate 	for (mech_idx = 0; mech_idx < desc->pd_mech_list_count;
8110Sstevel@tonic-gate 	    mech_idx++) {
8120Sstevel@tonic-gate 		kcf_remove_mech_provider(
8130Sstevel@tonic-gate 		    desc->pd_mechanisms[mech_idx].cm_mech_name, desc);
8140Sstevel@tonic-gate 	}
8150Sstevel@tonic-gate 
8160Sstevel@tonic-gate 	/* remove provider from providers table */
8170Sstevel@tonic-gate 	if (remove_prov)
8180Sstevel@tonic-gate 		(void) kcf_prov_tab_rem_provider(desc->pd_prov_id);
8190Sstevel@tonic-gate }
8200Sstevel@tonic-gate 
8210Sstevel@tonic-gate /*
8220Sstevel@tonic-gate  * Utility routine called from crypto_load_soft_disabled(). Callers
8230Sstevel@tonic-gate  * should have done a prior undo_register_provider().
8240Sstevel@tonic-gate  */
8250Sstevel@tonic-gate void
8260Sstevel@tonic-gate redo_register_provider(kcf_provider_desc_t *pd)
8270Sstevel@tonic-gate {
8280Sstevel@tonic-gate 	/* process the mechanisms supported by the provider */
8290Sstevel@tonic-gate 	(void) init_prov_mechs(NULL, pd);
8300Sstevel@tonic-gate 
8310Sstevel@tonic-gate 	/*
8320Sstevel@tonic-gate 	 * Hold provider in providers table. We should not call
8330Sstevel@tonic-gate 	 * kcf_prov_tab_add_provider() here as the provider descriptor
8340Sstevel@tonic-gate 	 * is still valid which means it has an entry in the provider
8350Sstevel@tonic-gate 	 * table.
8360Sstevel@tonic-gate 	 */
8370Sstevel@tonic-gate 	KCF_PROV_REFHOLD(pd);
8380Sstevel@tonic-gate 	KCF_PROV_IREFHOLD(pd);
8390Sstevel@tonic-gate }
8400Sstevel@tonic-gate 
8410Sstevel@tonic-gate /*
8420Sstevel@tonic-gate  * Add provider (p1) to another provider's array of providers (p2).
8430Sstevel@tonic-gate  * Hardware and logical providers use this array to cross-reference
8440Sstevel@tonic-gate  * each other.
8450Sstevel@tonic-gate  */
8460Sstevel@tonic-gate static void
8470Sstevel@tonic-gate add_provider_to_array(kcf_provider_desc_t *p1, kcf_provider_desc_t *p2)
8480Sstevel@tonic-gate {
8490Sstevel@tonic-gate 	kcf_provider_list_t *new;
8500Sstevel@tonic-gate 
8510Sstevel@tonic-gate 	new = kmem_alloc(sizeof (kcf_provider_list_t), KM_SLEEP);
8520Sstevel@tonic-gate 	mutex_enter(&p2->pd_lock);
8530Sstevel@tonic-gate 	new->pl_next = p2->pd_provider_list;
8540Sstevel@tonic-gate 	p2->pd_provider_list = new;
8550Sstevel@tonic-gate 	KCF_PROV_IREFHOLD(p1);
8560Sstevel@tonic-gate 	new->pl_provider = p1;
8570Sstevel@tonic-gate 	mutex_exit(&p2->pd_lock);
8580Sstevel@tonic-gate }
8590Sstevel@tonic-gate 
8600Sstevel@tonic-gate /*
8610Sstevel@tonic-gate  * Remove provider (p1) from another provider's array of providers (p2).
8620Sstevel@tonic-gate  * Hardware and logical providers use this array to cross-reference
8630Sstevel@tonic-gate  * each other.
8640Sstevel@tonic-gate  */
8650Sstevel@tonic-gate static void
8660Sstevel@tonic-gate remove_provider_from_array(kcf_provider_desc_t *p1, kcf_provider_desc_t *p2)
8670Sstevel@tonic-gate {
8680Sstevel@tonic-gate 
8690Sstevel@tonic-gate 	kcf_provider_list_t *pl = NULL, **prev;
8700Sstevel@tonic-gate 
8710Sstevel@tonic-gate 	mutex_enter(&p2->pd_lock);
8720Sstevel@tonic-gate 	for (pl = p2->pd_provider_list, prev = &p2->pd_provider_list;
8730Sstevel@tonic-gate 	    pl != NULL; prev = &pl->pl_next, pl = pl->pl_next) {
8740Sstevel@tonic-gate 		if (pl->pl_provider == p1) {
8750Sstevel@tonic-gate 			break;
8760Sstevel@tonic-gate 		}
8770Sstevel@tonic-gate 	}
8780Sstevel@tonic-gate 
8790Sstevel@tonic-gate 	if (p1 == NULL) {
8800Sstevel@tonic-gate 		mutex_exit(&p2->pd_lock);
8810Sstevel@tonic-gate 		return;
8820Sstevel@tonic-gate 	}
8830Sstevel@tonic-gate 
8840Sstevel@tonic-gate 	/* detach and free kcf_provider_list structure */
8850Sstevel@tonic-gate 	KCF_PROV_IREFRELE(p1);
8860Sstevel@tonic-gate 	*prev = pl->pl_next;
8870Sstevel@tonic-gate 	kmem_free(pl, sizeof (*pl));
8880Sstevel@tonic-gate 	mutex_exit(&p2->pd_lock);
8890Sstevel@tonic-gate }
8900Sstevel@tonic-gate 
8910Sstevel@tonic-gate /*
8920Sstevel@tonic-gate  * Convert an array of logical provider handles (crypto_provider_id)
8930Sstevel@tonic-gate  * stored in a crypto_provider_info structure into an array of provider
8940Sstevel@tonic-gate  * descriptors (kcf_provider_desc_t) attached to a logical provider.
8950Sstevel@tonic-gate  */
8960Sstevel@tonic-gate static void
8970Sstevel@tonic-gate process_logical_providers(crypto_provider_info_t *info, kcf_provider_desc_t *hp)
8980Sstevel@tonic-gate {
8990Sstevel@tonic-gate 	kcf_provider_desc_t *lp;
9000Sstevel@tonic-gate 	crypto_provider_id_t handle;
9010Sstevel@tonic-gate 	int count = info->pi_logical_provider_count;
9020Sstevel@tonic-gate 	int i;
9030Sstevel@tonic-gate 
9040Sstevel@tonic-gate 	/* add hardware provider to each logical provider */
9050Sstevel@tonic-gate 	for (i = 0; i < count; i++) {
9060Sstevel@tonic-gate 		handle = info->pi_logical_providers[i];
9070Sstevel@tonic-gate 		lp = kcf_prov_tab_lookup((crypto_provider_id_t)handle);
9080Sstevel@tonic-gate 		if (lp == NULL) {
9090Sstevel@tonic-gate 			continue;
9100Sstevel@tonic-gate 		}
9110Sstevel@tonic-gate 		add_provider_to_array(hp, lp);
9120Sstevel@tonic-gate 
9130Sstevel@tonic-gate 		/*
9140Sstevel@tonic-gate 		 * A hardware provider has to have the provider descriptor of
9150Sstevel@tonic-gate 		 * every logical provider it belongs to, so it can be removed
9160Sstevel@tonic-gate 		 * from the logical provider if the hardware provider
9170Sstevel@tonic-gate 		 * unregisters from the framework.
9180Sstevel@tonic-gate 		 */
9190Sstevel@tonic-gate 		add_provider_to_array(lp, hp);
9200Sstevel@tonic-gate 		KCF_PROV_REFRELE(lp);
9210Sstevel@tonic-gate 	}
9220Sstevel@tonic-gate }
9230Sstevel@tonic-gate 
9240Sstevel@tonic-gate /*
9250Sstevel@tonic-gate  * This routine removes a provider from all of the logical or
9260Sstevel@tonic-gate  * hardware providers it belongs to, and frees the provider's
9270Sstevel@tonic-gate  * array of pointers to providers.
9280Sstevel@tonic-gate  */
9290Sstevel@tonic-gate static void
9300Sstevel@tonic-gate remove_provider(kcf_provider_desc_t *pp)
9310Sstevel@tonic-gate {
9320Sstevel@tonic-gate 	kcf_provider_desc_t *p;
9330Sstevel@tonic-gate 	kcf_provider_list_t *e, *next;
9340Sstevel@tonic-gate 
9350Sstevel@tonic-gate 	mutex_enter(&pp->pd_lock);
9360Sstevel@tonic-gate 	for (e = pp->pd_provider_list; e != NULL; e = next) {
9370Sstevel@tonic-gate 		p = e->pl_provider;
9380Sstevel@tonic-gate 		remove_provider_from_array(pp, p);
9390Sstevel@tonic-gate 		KCF_PROV_IREFRELE(p);
9400Sstevel@tonic-gate 		next = e->pl_next;
9410Sstevel@tonic-gate 		kmem_free(e, sizeof (*e));
9420Sstevel@tonic-gate 	}
9430Sstevel@tonic-gate 	pp->pd_provider_list = NULL;
9440Sstevel@tonic-gate 	mutex_exit(&pp->pd_lock);
9450Sstevel@tonic-gate }
946