xref: /onnv-gate/usr/src/uts/sun4u/starcat/io/sckmdrv.c (revision 11311:639e7bc0b42f)
11708Sstevel /*
21708Sstevel  * CDDL HEADER START
31708Sstevel  *
41708Sstevel  * The contents of this file are subject to the terms of the
51708Sstevel  * Common Development and Distribution License (the "License").
61708Sstevel  * You may not use this file except in compliance with the License.
71708Sstevel  *
81708Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91708Sstevel  * or http://www.opensolaris.org/os/licensing.
101708Sstevel  * See the License for the specific language governing permissions
111708Sstevel  * and limitations under the License.
121708Sstevel  *
131708Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
141708Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151708Sstevel  * If applicable, add the following below this CDDL HEADER, with the
161708Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
171708Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
181708Sstevel  *
191708Sstevel  * CDDL HEADER END
201708Sstevel  */
211708Sstevel 
221708Sstevel /*
2311066Srafael.vanoni@sun.com  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
241708Sstevel  * Use is subject to license terms.
251708Sstevel  */
261708Sstevel 
271708Sstevel 
281708Sstevel /*
291708Sstevel  * Starcat IPSec Key Management Driver.
301708Sstevel  *
311708Sstevel  * This driver runs on a Starcat Domain. It processes requests received
321708Sstevel  * from the System Controller (SC) from IOSRAM, passes these requests
331708Sstevel  * to the sckmd daemon by means of an open/close/ioctl interface, and
341708Sstevel  * sends corresponding status information back to the SC.
351708Sstevel  *
361708Sstevel  * Requests received from the SC consist of IPsec security associations
371708Sstevel  * (SAs) needed to secure the communication between SC and Domain daemons
381708Sstevel  * communicating using the Management Network (MAN).
391708Sstevel  */
401708Sstevel 
411708Sstevel #include <sys/types.h>
421708Sstevel #include <sys/cmn_err.h>
431708Sstevel #include <sys/kmem.h>
441708Sstevel #include <sys/errno.h>
451708Sstevel #include <sys/file.h>
461708Sstevel #include <sys/open.h>
471708Sstevel #include <sys/stat.h>
481708Sstevel #include <sys/conf.h>
491708Sstevel #include <sys/ddi.h>
501708Sstevel #include <sys/cmn_err.h>
511708Sstevel #include <sys/sunddi.h>
521708Sstevel #include <sys/sunndi.h>
531708Sstevel #include <sys/ddi_impldefs.h>
541708Sstevel #include <sys/ndi_impldefs.h>
551708Sstevel #include <sys/modctl.h>
561708Sstevel #include <sys/disp.h>
571708Sstevel #include <sys/async.h>
581708Sstevel #include <sys/mboxsc.h>
591708Sstevel #include <sys/sckm_msg.h>
601708Sstevel #include <sys/sckm_io.h>
611708Sstevel #include <sys/taskq.h>
621708Sstevel #include <sys/note.h>
631708Sstevel 
641708Sstevel #ifdef DEBUG
651708Sstevel static uint_t sckm_debug_flags = 0x0;
661708Sstevel #define	SCKM_DEBUG0(f, s) if ((f)& sckm_debug_flags) \
671708Sstevel 	cmn_err(CE_CONT, s)
681708Sstevel #define	SCKM_DEBUG1(f, s, a) if ((f)& sckm_debug_flags) \
691708Sstevel 	cmn_err(CE_CONT, s, a)
701708Sstevel #define	SCKM_DEBUG2(f, s, a, b) if ((f)& sckm_debug_flags) \
711708Sstevel 	cmn_err(CE_CONT, s, a, b)
721708Sstevel #define	SCKM_DEBUG3(f, s, a, b, c) if ((f)& sckm_debug_flags) \
731708Sstevel 	cmn_err(CE_CONT, s, a, b, c)
741708Sstevel #define	SCKM_DEBUG4(f, s, a, b, c, d) if ((f)& sckm_debug_flags) \
751708Sstevel 	cmn_err(CE_CONT, s, a, b, c, d)
761708Sstevel #define	SCKM_DEBUG5(f, s, a, b, c, d, e) if ((f)& sckm_debug_flags) \
771708Sstevel 	cmn_err(CE_CONT, s, a, b, c, d, e)
781708Sstevel #define	SCKM_DEBUG6(f, s, a, b, c, d, e, ff) if ((f)& sckm_debug_flags) \
791708Sstevel 	cmn_err(CE_CONT, s, a, b, c, d, e, ff)
801708Sstevel #else
811708Sstevel #define	SCKM_DEBUG0(f, s)
821708Sstevel #define	SCKM_DEBUG1(f, s, a)
831708Sstevel #define	SCKM_DEBUG2(f, s, a, b)
841708Sstevel #define	SCKM_DEBUG3(f, s, a, b, c)
851708Sstevel #define	SCKM_DEBUG4(f, s, a, b, c, d)
861708Sstevel #define	SCKM_DEBUG5(f, s, a, b, c, d, e)
871708Sstevel #define	SCKM_DEBUG6(f, s, a, b, c, d, e, ff)
881708Sstevel #endif /* DEBUG */
891708Sstevel 
901708Sstevel #define	D_INIT		0x00000001	/* _init/_fini/_info */
911708Sstevel #define	D_ATTACH	0x00000002	/* attach/detach */
921708Sstevel #define	D_OPEN		0x00000008	/* open/close */
931708Sstevel #define	D_IOCTL		0x00010000	/* ioctl */
941708Sstevel #define	D_TASK		0x00100000	/* mailbox task processing */
951708Sstevel #define	D_CALLBACK	0x00200000	/* mailbox callback */
961708Sstevel 
971708Sstevel static int sckm_open(dev_t *, int, int, struct cred *);
981708Sstevel static int sckm_close(dev_t, int, int, struct cred *);
991708Sstevel static int sckm_ioctl(dev_t, int, intptr_t, int, struct cred *, int *);
1001708Sstevel 
1011708Sstevel static struct cb_ops sckm_cb_ops = {
1021708Sstevel 	sckm_open,		/* open */
1031708Sstevel 	sckm_close,		/* close */
1041708Sstevel 	nodev,			/* strategy */
1051708Sstevel 	nodev,			/* print */
1061708Sstevel 	nodev,			/* dump */
1071708Sstevel 	nodev,			/* read */
1081708Sstevel 	nodev,			/* write */
1091708Sstevel 	sckm_ioctl,		/* ioctl */
1101708Sstevel 	nodev,			/* devmap */
1111708Sstevel 	nodev,			/* mmap */
1121708Sstevel 	nodev,			/* segmap */
1131708Sstevel 	nochpoll,		/* poll */
1141708Sstevel 	ddi_prop_op,		/* prop_op */
1151708Sstevel 	0,			/* streamtab  */
1161708Sstevel 	D_NEW | D_MP		/* Driver compatibility flag */
1171708Sstevel };
1181708Sstevel 
1191708Sstevel static int sckm_attach(dev_info_t *, ddi_attach_cmd_t);
1201708Sstevel static int sckm_detach(dev_info_t *, ddi_detach_cmd_t);
1211708Sstevel static int sckm_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
1221708Sstevel 
1231708Sstevel static struct dev_ops sckm_ops = {
1241708Sstevel 	DEVO_REV,		/* devo_rev, */
1251708Sstevel 	0,			/* refcnt  */
1261708Sstevel 	sckm_info,		/* get_dev_info */
1271708Sstevel 	nulldev,		/* identify */
1281708Sstevel 	nulldev,		/* probe */
1291708Sstevel 	sckm_attach,		/* attach */
1301708Sstevel 	sckm_detach,		/* detach */
1311708Sstevel 	nodev,			/* reset */
1321708Sstevel 	&sckm_cb_ops,		/* driver operations */
1337656SSherry.Moore@Sun.COM 	(struct bus_ops *)0,	/* no bus operations */
1347656SSherry.Moore@Sun.COM 	NULL,			/* power */
1357656SSherry.Moore@Sun.COM 	ddi_quiesce_not_needed,		/* quiesce */
1361708Sstevel };
1371708Sstevel 
1381708Sstevel static struct modldrv modldrv = {
1391708Sstevel 	&mod_driverops,
1407656SSherry.Moore@Sun.COM 	"Key Management Driver",
1411708Sstevel 	&sckm_ops,
1421708Sstevel };
1431708Sstevel 
1441708Sstevel static struct modlinkage modlinkage = {
1451708Sstevel 	MODREV_1,
1461708Sstevel 	&modldrv,
1471708Sstevel 	NULL
1481708Sstevel };
1491708Sstevel 
1501708Sstevel /*
1511708Sstevel  * Private definitions.
1521708Sstevel  */
1531708Sstevel #define	SCKM_DEF_GETMSG_TIMEOUT 60	/* in seconds */
1541708Sstevel #define	SCKM_DAEMON_TIMEOUT	4000000	/* in microseconds */
1551708Sstevel #define	SCKM_NUM_TASKQ		2	/* # of task queue entries */
1561708Sstevel 
1571708Sstevel /*
1581708Sstevel  * For processing mailbox layer events.
1591708Sstevel  */
1601708Sstevel static kmutex_t sckm_task_mutex;
1611708Sstevel static kmutex_t sckm_taskq_ptr_mutex;
1621708Sstevel static clock_t sckm_getmsg_timeout = SCKM_DEF_GETMSG_TIMEOUT*1000;
1631708Sstevel static taskq_t *sckm_taskq = NULL;
1641708Sstevel static sckm_mbox_req_hdr_t *req_data = NULL;
1651708Sstevel static sckm_mbox_rep_hdr_t *rep_data = NULL;
1661708Sstevel 
1671708Sstevel 
1681708Sstevel /*
1691708Sstevel  * For synchronization with key management daemon.
1701708Sstevel  */
1711708Sstevel static kmutex_t sckm_umutex;
1721708Sstevel static kcondvar_t sckm_udata_cv;	/* daemon waits on data */
1731708Sstevel static kcondvar_t sckm_cons_cv;		/* wait for daemon to consume data */
1741708Sstevel static boolean_t sckm_udata_req = B_FALSE; /* data available for daemon */
1751708Sstevel static sckm_ioctl_getreq_t sckm_udata;	/* request for daemon */
1761708Sstevel static sckm_ioctl_status_t sckm_udata_status; /* status from daemon */
1771708Sstevel 
1781708Sstevel /*
1791708Sstevel  * Other misc private variables.
1801708Sstevel  */
1811708Sstevel static dev_info_t *sckm_devi = NULL;
1821708Sstevel static boolean_t sckm_oflag = B_FALSE;
1831708Sstevel 
1841708Sstevel /*
1851708Sstevel  * Private functions prototypes.
1861708Sstevel  */
1871708Sstevel static void sckm_mbox_callback(void);
1881708Sstevel static void sckm_mbox_task(void *arg);
1891708Sstevel static void sckm_process_msg(uint32_t cmd, uint64_t transid,
1901708Sstevel     uint32_t len, sckm_mbox_req_hdr_t *req_data,
1911708Sstevel     sckm_mbox_rep_hdr_t *rep_data);
1921708Sstevel 
1931708Sstevel 
1941708Sstevel int
_init(void)1951708Sstevel _init(void)
1961708Sstevel {
1971708Sstevel 	mboxsc_timeout_range_t timeout_range;
1981708Sstevel 	int ret;
1991708Sstevel 
2001708Sstevel 	SCKM_DEBUG0(D_INIT, "in _init");
2011708Sstevel 
2021708Sstevel 	/*
2031708Sstevel 	 * Initialize outgoing mailbox (KDSC)
2041708Sstevel 	 */
2051708Sstevel 	if ((ret = mboxsc_init(KEY_KDSC, MBOXSC_MBOX_OUT, NULL)) != 0) {
2061708Sstevel 		cmn_err(CE_WARN, "failed initializing outgoing mailbox "
2071708Sstevel 		    "(%d)", ret);
2081708Sstevel 		return (ret);
2091708Sstevel 	}
2101708Sstevel 
2111708Sstevel 	/*
2121708Sstevel 	 * Initialize incoming mailbox (SCKD)
2131708Sstevel 	 */
2141708Sstevel 	if ((ret = mboxsc_init(KEY_SCKD, MBOXSC_MBOX_IN,
2151708Sstevel 	    sckm_mbox_callback)) != 0) {
2161708Sstevel 		cmn_err(CE_WARN, "failed initializing incoming mailbox "
2171708Sstevel 		    "(%d)\n", ret);
218*11311SSurya.Prakki@Sun.COM 		(void) mboxsc_fini(KEY_KDSC);
2191708Sstevel 		return (ret);
2201708Sstevel 	}
2211708Sstevel 
2221708Sstevel 	if ((ret = mboxsc_ctrl(KEY_SCKD, MBOXSC_CMD_GETMSG_TIMEOUT_RANGE,
2231708Sstevel 	    (void *)&timeout_range)) != 0) {
224*11311SSurya.Prakki@Sun.COM 		(void) mboxsc_fini(KEY_SCKD);
225*11311SSurya.Prakki@Sun.COM 		(void) mboxsc_fini(KEY_KDSC);
2261708Sstevel 		return (ret);
2271708Sstevel 	}
2281708Sstevel 
2291708Sstevel 	if (sckm_getmsg_timeout < timeout_range.min_timeout) {
2301708Sstevel 		sckm_getmsg_timeout = timeout_range.min_timeout;
2311708Sstevel 		cmn_err(CE_WARN, "resetting getmsg timeout to %lx",
2321708Sstevel 		    sckm_getmsg_timeout);
2331708Sstevel 	}
2341708Sstevel 
2351708Sstevel 	if (sckm_getmsg_timeout > timeout_range.max_timeout) {
2361708Sstevel 		sckm_getmsg_timeout = timeout_range.max_timeout;
2371708Sstevel 		cmn_err(CE_WARN, "resetting getmsg timeout to %lx",
2381708Sstevel 		    sckm_getmsg_timeout);
2391708Sstevel 	}
2401708Sstevel 
2411708Sstevel 	if ((ret = mod_install(&modlinkage)) != 0) {
242*11311SSurya.Prakki@Sun.COM 		(void) mboxsc_fini(KEY_KDSC);
243*11311SSurya.Prakki@Sun.COM 		(void) mboxsc_fini(KEY_SCKD);
2441708Sstevel 		return (ret);
2451708Sstevel 	}
2461708Sstevel 
2471708Sstevel 	/*
2481708Sstevel 	 * Initialize variables needed for synchronization with daemon.
2491708Sstevel 	 */
2501708Sstevel 	sckm_udata.buf = kmem_alloc(SCKM_SCKD_MAXDATA, KM_SLEEP);
2511708Sstevel 	req_data = (sckm_mbox_req_hdr_t *)kmem_alloc(SCKM_SCKD_MAXDATA,
2521708Sstevel 	    KM_SLEEP);
2531708Sstevel 	rep_data = (sckm_mbox_rep_hdr_t *)kmem_alloc(SCKM_KDSC_MAXDATA,
2541708Sstevel 	    KM_SLEEP);
2551708Sstevel 
2561708Sstevel 	if ((sckm_udata.buf == NULL) || (req_data == NULL) ||
2571708Sstevel 	    (rep_data == NULL)) {
2581708Sstevel 		cmn_err(CE_WARN, "not enough memory during _init");
2591708Sstevel 
2601708Sstevel 		/* free what was successfully allocated */
2611708Sstevel 		if (sckm_udata.buf != NULL)
2621708Sstevel 			kmem_free(sckm_udata.buf, SCKM_SCKD_MAXDATA);
2631708Sstevel 		if (req_data != NULL)
2641708Sstevel 			kmem_free(req_data, SCKM_SCKD_MAXDATA);
2651708Sstevel 		if (rep_data != NULL)
2661708Sstevel 			kmem_free(rep_data, SCKM_KDSC_MAXDATA);
2671708Sstevel 		sckm_udata.buf = NULL;
2681708Sstevel 		req_data = NULL;
2691708Sstevel 		rep_data = NULL;
2701708Sstevel 
2711708Sstevel 		/* uninitialize mailboxes, remove module, and return error */
272*11311SSurya.Prakki@Sun.COM 		(void) mboxsc_fini(KEY_KDSC);
273*11311SSurya.Prakki@Sun.COM 		(void) mboxsc_fini(KEY_SCKD);
274*11311SSurya.Prakki@Sun.COM 		(void) mod_remove(&modlinkage);
2751708Sstevel 		return (-1);
2761708Sstevel 	}
2771708Sstevel 
2781708Sstevel 	cv_init(&sckm_udata_cv, NULL, CV_DRIVER, NULL);
2791708Sstevel 	cv_init(&sckm_cons_cv, NULL, CV_DRIVER, NULL);
2801708Sstevel 	mutex_init(&sckm_umutex, NULL, MUTEX_DRIVER, NULL);
2811708Sstevel 
2821708Sstevel 	/*
2831708Sstevel 	 * Create mutex for task processing, protection of taskq
2841708Sstevel 	 * pointer, and create taskq.
2851708Sstevel 	 */
2861708Sstevel 	mutex_init(&sckm_task_mutex, NULL, MUTEX_DRIVER, NULL);
2871708Sstevel 	mutex_init(&sckm_taskq_ptr_mutex, NULL, MUTEX_DRIVER, NULL);
2881708Sstevel 	sckm_taskq = taskq_create("sckm_taskq", 1, minclsyspri,
2891708Sstevel 	    SCKM_NUM_TASKQ, SCKM_NUM_TASKQ, TASKQ_PREPOPULATE);
2901708Sstevel 
2911708Sstevel 	SCKM_DEBUG1(D_INIT, "out _init ret=%d\n", ret);
2921708Sstevel 	return (ret);
2931708Sstevel }
2941708Sstevel 
2951708Sstevel int
_fini(void)2961708Sstevel _fini(void)
2971708Sstevel {
2981708Sstevel 	int ret;
2991708Sstevel 
3001708Sstevel 	SCKM_DEBUG0(D_INIT, "in _fini");
3011708Sstevel 
3021708Sstevel 	if ((ret = mod_remove(&modlinkage)) != 0) {
3031708Sstevel 		return (ret);
3041708Sstevel 	}
3051708Sstevel 
3061708Sstevel 	/*
3071708Sstevel 	 * Wait for scheduled tasks to complete, then destroy task queue.
3081708Sstevel 	 */
3091708Sstevel 	mutex_enter(&sckm_taskq_ptr_mutex);
3101708Sstevel 	if (sckm_taskq != NULL) {
3111708Sstevel 		taskq_destroy(sckm_taskq);
3121708Sstevel 		sckm_taskq = NULL;
3131708Sstevel 	}
3141708Sstevel 	mutex_exit(&sckm_taskq_ptr_mutex);
3151708Sstevel 
3161708Sstevel 	/*
3171708Sstevel 	 * Terminate incoming and outgoing IOSRAM mailboxes
3181708Sstevel 	 */
319*11311SSurya.Prakki@Sun.COM 	(void) mboxsc_fini(KEY_KDSC);
320*11311SSurya.Prakki@Sun.COM 	(void) mboxsc_fini(KEY_SCKD);
3211708Sstevel 
3221708Sstevel 	/*
3231708Sstevel 	 * Destroy module synchronization objects and free memory
3241708Sstevel 	 */
3251708Sstevel 	mutex_destroy(&sckm_task_mutex);
3261708Sstevel 	mutex_destroy(&sckm_taskq_ptr_mutex);
3271708Sstevel 	mutex_destroy(&sckm_umutex);
3281708Sstevel 	cv_destroy(&sckm_cons_cv);
3291708Sstevel 
3301708Sstevel 	if (sckm_udata.buf != NULL) {
3311708Sstevel 		kmem_free(sckm_udata.buf, SCKM_SCKD_MAXDATA);
3321708Sstevel 		sckm_udata.buf = NULL;
3331708Sstevel 	}
3341708Sstevel 	if (rep_data != NULL) {
3351708Sstevel 		kmem_free(rep_data, SCKM_KDSC_MAXDATA);
3361708Sstevel 		rep_data = NULL;
3371708Sstevel 	}
3381708Sstevel 	if (req_data != NULL) {
3391708Sstevel 		kmem_free(req_data, SCKM_SCKD_MAXDATA);
3401708Sstevel 		req_data = NULL;
3411708Sstevel 	}
3421708Sstevel 
3431708Sstevel 	return (ret);
3441708Sstevel }
3451708Sstevel 
3461708Sstevel int
_info(struct modinfo * modinfop)3471708Sstevel _info(struct modinfo *modinfop)
3481708Sstevel {
3491708Sstevel 	SCKM_DEBUG0(D_INIT, "in _info");
3501708Sstevel 	return (mod_info(&modlinkage, modinfop));
3511708Sstevel }
3521708Sstevel 
3531708Sstevel static int
sckm_attach(dev_info_t * devi,ddi_attach_cmd_t cmd)3541708Sstevel sckm_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
3551708Sstevel {
3561708Sstevel 	SCKM_DEBUG1(D_ATTACH, "in sckm_attach, cmd=%d", cmd);
3571708Sstevel 
3581708Sstevel 	switch (cmd) {
3591708Sstevel 	case DDI_ATTACH:
3601708Sstevel 		SCKM_DEBUG0(D_ATTACH, "sckm_attach: DDI_ATTACH");
3611708Sstevel 		if (ddi_create_minor_node(devi, "sckmdrv", S_IFCHR,
3621708Sstevel 		    0, NULL, NULL) == DDI_FAILURE) {
3631708Sstevel 			cmn_err(CE_WARN, "ddi_create_minor_node failed");
3641708Sstevel 			ddi_remove_minor_node(devi, NULL);
3651708Sstevel 			return (DDI_FAILURE);
3661708Sstevel 		}
3671708Sstevel 		sckm_devi = devi;
3681708Sstevel 		break;
3691708Sstevel 	case DDI_SUSPEND:
3701708Sstevel 		SCKM_DEBUG0(D_ATTACH, "sckm_attach: DDI_SUSPEND");
3711708Sstevel 		break;
3721708Sstevel 	default:
3731708Sstevel 		cmn_err(CE_WARN, "sckm_attach: bad cmd %d\n", cmd);
3741708Sstevel 		return (DDI_FAILURE);
3751708Sstevel 	}
3761708Sstevel 
3771708Sstevel 	SCKM_DEBUG0(D_ATTACH, "out sckm_attach (DDI_SUCCESS)");
3781708Sstevel 	return (DDI_SUCCESS);
3791708Sstevel }
3801708Sstevel 
3811708Sstevel static int
sckm_detach(dev_info_t * devi,ddi_detach_cmd_t cmd)3821708Sstevel sckm_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
3831708Sstevel {
3841708Sstevel 	SCKM_DEBUG1(D_ATTACH, "in sckm_detach, cmd=%d", cmd);
3851708Sstevel 
3861708Sstevel 	switch (cmd) {
3871708Sstevel 	case DDI_DETACH:
3881708Sstevel 		SCKM_DEBUG0(D_ATTACH, "sckm_detach: DDI_DETACH");
3891708Sstevel 		ddi_remove_minor_node(devi, NULL);
3901708Sstevel 		break;
3911708Sstevel 	case DDI_SUSPEND:
3921708Sstevel 		SCKM_DEBUG0(D_ATTACH, "sckm_detach: DDI_DETACH");
3931708Sstevel 		break;
3941708Sstevel 	default:
3951708Sstevel 		cmn_err(CE_WARN, "sckm_detach: bad cmd %d\n", cmd);
3961708Sstevel 		return (DDI_FAILURE);
3971708Sstevel 	}
3981708Sstevel 
3991708Sstevel 	SCKM_DEBUG0(D_ATTACH, "out sckm_detach (DDI_SUCCESS)");
4001708Sstevel 	return (DDI_SUCCESS);
4011708Sstevel }
4021708Sstevel 
4031708Sstevel /* ARGSUSED */
4041708Sstevel static int
sckm_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)4051708Sstevel sckm_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
4061708Sstevel     void **result)
4071708Sstevel {
4081708Sstevel 	int rv;
4091708Sstevel 
4101708Sstevel 	SCKM_DEBUG1(D_ATTACH, "in sckm_info, infocmd=%d", infocmd);
4111708Sstevel 
4121708Sstevel 	switch (infocmd) {
4131708Sstevel 	case DDI_INFO_DEVT2DEVINFO:
4141708Sstevel 		*result = (void *)sckm_devi;
4151708Sstevel 		rv = DDI_SUCCESS;
4161708Sstevel 		break;
4171708Sstevel 	case DDI_INFO_DEVT2INSTANCE:
4181708Sstevel 		*result = (void *)0;
4191708Sstevel 		rv = DDI_SUCCESS;
4201708Sstevel 		break;
4211708Sstevel 	default:
4221708Sstevel 		rv = DDI_FAILURE;
4231708Sstevel 	}
4241708Sstevel 
4251708Sstevel 	SCKM_DEBUG1(D_ATTACH, "out sckm_info, rv=%d", rv);
4261708Sstevel 	return (rv);
4271708Sstevel }
4281708Sstevel 
4291708Sstevel /*ARGSUSED*/
4301708Sstevel static int
sckm_open(dev_t * devp,int flag,int otyp,struct cred * cred)4311708Sstevel sckm_open(dev_t *devp, int flag, int otyp, struct cred *cred)
4321708Sstevel {
4331708Sstevel 	SCKM_DEBUG0(D_OPEN, "in sckm_open");
4341708Sstevel 
4351708Sstevel 	/* check credentials of calling process */
4361708Sstevel 	if (drv_priv(cred)) {
4371708Sstevel 		SCKM_DEBUG0(D_OPEN, "sckm_open: attempt by non-root proc");
4381708Sstevel 		return (EPERM);
4391708Sstevel 	}
4401708Sstevel 
4411708Sstevel 	/* enforce exclusive access */
4421708Sstevel 	mutex_enter(&sckm_umutex);
4431708Sstevel 	if (sckm_oflag == B_TRUE) {
4441708Sstevel 		SCKM_DEBUG0(D_OPEN, "sckm_open: already open");
4451708Sstevel 		mutex_exit(&sckm_umutex);
4461708Sstevel 		return (EBUSY);
4471708Sstevel 	}
4481708Sstevel 	sckm_oflag = B_TRUE;
4491708Sstevel 	mutex_exit(&sckm_umutex);
4501708Sstevel 
4511708Sstevel 	SCKM_DEBUG0(D_OPEN, "sckm_open: succcess");
4521708Sstevel 	return (0);
4531708Sstevel }
4541708Sstevel 
4551708Sstevel /*ARGSUSED*/
4561708Sstevel static int
sckm_close(dev_t dev,int flag,int otyp,struct cred * cred)4571708Sstevel sckm_close(dev_t dev, int flag, int otyp, struct cred *cred)
4581708Sstevel {
4591708Sstevel 	SCKM_DEBUG0(D_OPEN, "in sckm_close");
4601708Sstevel 
4611708Sstevel 	mutex_enter(&sckm_umutex);
4621708Sstevel 	sckm_oflag = B_FALSE;
4631708Sstevel 	mutex_exit(&sckm_umutex);
4641708Sstevel 
4651708Sstevel 	return (0);
4661708Sstevel }
4671708Sstevel 
4681708Sstevel 
4691708Sstevel static int
sckm_copyin_ioctl_getreq(intptr_t userarg,sckm_ioctl_getreq_t * driverarg,int flag)4701708Sstevel sckm_copyin_ioctl_getreq(intptr_t userarg, sckm_ioctl_getreq_t *driverarg,
4711708Sstevel     int flag)
4721708Sstevel {
4731708Sstevel #ifdef _MULTI_DATAMODEL
4741708Sstevel 	switch (ddi_model_convert_from(flag & FMODELS)) {
4751708Sstevel 	case DDI_MODEL_ILP32: {
4761708Sstevel 		sckm_ioctl_getreq32_t driverarg32;
4771708Sstevel 		if (ddi_copyin((caddr_t)userarg, &driverarg32,
4781708Sstevel 		    sizeof (sckm_ioctl_getreq32_t), flag)) {
4791708Sstevel 			return (EFAULT);
4801708Sstevel 		}
4811708Sstevel 		driverarg->transid = driverarg32.transid;
4821708Sstevel 		driverarg->type = driverarg32.type;
4831708Sstevel 		driverarg->buf = (caddr_t)(uintptr_t)driverarg32.buf;
4841708Sstevel 		driverarg->buf_len = driverarg32.buf_len;
4851708Sstevel 		break;
4861708Sstevel 	}
4871708Sstevel 	case DDI_MODEL_NONE: {
4881708Sstevel 		if (ddi_copyin((caddr_t)userarg, &driverarg,
4891708Sstevel 		    sizeof (sckm_ioctl_getreq_t), flag)) {
4901708Sstevel 			return (EFAULT);
4911708Sstevel 		}
4921708Sstevel 		break;
4931708Sstevel 	}
4941708Sstevel 	}
4951708Sstevel #else /* ! _MULTI_DATAMODEL */
4961708Sstevel 	if (ddi_copyin((caddr_t)userarg, &driverarg,
4971708Sstevel 	    sizeof (sckm_ioctl_getreq_t), flag)) {
4981708Sstevel 		return (EFAULT);
4991708Sstevel 	}
5001708Sstevel #endif /* _MULTI_DATAMODEL */
5011708Sstevel 	return (0);
5021708Sstevel }
5031708Sstevel 
5041708Sstevel 
5051708Sstevel static int
sckm_copyout_ioctl_getreq(sckm_ioctl_getreq_t * driverarg,intptr_t userarg,int flag)5061708Sstevel sckm_copyout_ioctl_getreq(sckm_ioctl_getreq_t *driverarg, intptr_t userarg,
5071708Sstevel     int flag)
5081708Sstevel {
5091708Sstevel #ifdef _MULTI_DATAMODEL
5101708Sstevel 	switch (ddi_model_convert_from(flag & FMODELS)) {
5111708Sstevel 	case DDI_MODEL_ILP32: {
5121708Sstevel 		sckm_ioctl_getreq32_t driverarg32;
5131708Sstevel 		driverarg32.transid = driverarg->transid;
5141708Sstevel 		driverarg32.type = driverarg->type;
5151708Sstevel 		driverarg32.buf = (caddr32_t)(uintptr_t)driverarg->buf;
5161708Sstevel 		driverarg32.buf_len = driverarg->buf_len;
5171708Sstevel 		if (ddi_copyout(&driverarg32, (caddr_t)userarg,
5181708Sstevel 		    sizeof (sckm_ioctl_getreq32_t), flag)) {
5191708Sstevel 			return (EFAULT);
5201708Sstevel 		}
5211708Sstevel 		break;
5221708Sstevel 	}
5231708Sstevel 	case DDI_MODEL_NONE:
5241708Sstevel 		if (ddi_copyout(driverarg, (caddr_t)userarg,
5251708Sstevel 		    sizeof (sckm_ioctl_getreq_t), flag)) {
5261708Sstevel 			return (EFAULT);
5271708Sstevel 		}
5281708Sstevel 		break;
5291708Sstevel 	}
5301708Sstevel #else /* ! _MULTI_DATAMODEL */
5311708Sstevel 	if (ddi_copyout(driverarg, (caddr_t)userarg,
5321708Sstevel 	    sizeof (sckm_ioctl_getreq_t), flag)) {
5331708Sstevel 		return (EFAULT);
5341708Sstevel 	}
5351708Sstevel #endif /* _MULTI_DATAMODEL */
5361708Sstevel 	return (0);
5371708Sstevel }
5381708Sstevel 
5391708Sstevel 
5401708Sstevel /*ARGSUSED*/
5411708Sstevel static int
sckm_ioctl(dev_t dev,int cmd,intptr_t data,int flag,cred_t * cred,int * rvalp)5421708Sstevel sckm_ioctl(dev_t dev, int cmd, intptr_t data, int flag,
5431708Sstevel     cred_t *cred, int *rvalp)
5441708Sstevel {
5451708Sstevel 	int rval = 0;
5461708Sstevel 
5471708Sstevel 	SCKM_DEBUG0(D_IOCTL, "in sckm_ioctl");
5481708Sstevel 
5491708Sstevel 	switch (cmd) {
5501708Sstevel 	case SCKM_IOCTL_GETREQ: {
5511708Sstevel 		sckm_ioctl_getreq_t arg;
5521708Sstevel 
5531708Sstevel 		SCKM_DEBUG0(D_IOCTL, "sckm_ioctl: got SCKM_IOCTL_GETREQ");
5541708Sstevel 		if (sckm_copyin_ioctl_getreq(data, &arg, flag)) {
5551708Sstevel 			return (EFAULT);
5561708Sstevel 		}
5571708Sstevel 
5581708Sstevel 		/* sanity check argument */
5591708Sstevel 		if (arg.buf_len < SCKM_SCKD_MAXDATA) {
5601708Sstevel 			SCKM_DEBUG2(D_IOCTL, "sckm_ioctl: usr buffer too "
5611708Sstevel 			    "small (%d < %d)", arg.buf_len, SCKM_SCKD_MAXDATA);
5621708Sstevel 			return (ENOSPC);
5631708Sstevel 		}
5641708Sstevel 
5651708Sstevel 		mutex_enter(&sckm_umutex);
5661708Sstevel 
5671708Sstevel 		/* wait for request from SC */
5681708Sstevel 		while (!sckm_udata_req) {
5691708Sstevel 			SCKM_DEBUG0(D_IOCTL, "sckm_ioctl: waiting for msg");
5701708Sstevel 			if (cv_wait_sig(&sckm_udata_cv, &sckm_umutex) == 0) {
5711708Sstevel 				mutex_exit(&sckm_umutex);
5721708Sstevel 				return (EINTR);
5731708Sstevel 			}
5741708Sstevel 		}
5751708Sstevel 		SCKM_DEBUG1(D_IOCTL, "sckm_ioctl: msg available "
5767656SSherry.Moore@Sun.COM 		    "transid = 0x%lx", sckm_udata.transid);
5771708Sstevel 
5781708Sstevel 		arg.transid = sckm_udata.transid;
5791708Sstevel 		arg.type = sckm_udata.type;
5801708Sstevel 		if (ddi_copyout(sckm_udata.buf, arg.buf,
5811708Sstevel 		    sckm_udata.buf_len, flag)) {
5821708Sstevel 			mutex_exit(&sckm_umutex);
5831708Sstevel 			return (EFAULT);
5841708Sstevel 		}
5851708Sstevel 		arg.buf_len = sckm_udata.buf_len;
5861708Sstevel 
5871708Sstevel 		mutex_exit(&sckm_umutex);
5881708Sstevel 		if (sckm_copyout_ioctl_getreq(&arg, data, flag)) {
5891708Sstevel 			return (EFAULT);
5901708Sstevel 		}
5911708Sstevel 		break;
5921708Sstevel 	}
5931708Sstevel 	case SCKM_IOCTL_STATUS: {
5941708Sstevel 		sckm_ioctl_status_t arg;
5951708Sstevel 		SCKM_DEBUG0(D_IOCTL, "sckm_ioctl: got SCKM_IOCTL_STATUS");
5961708Sstevel 		if (ddi_copyin((caddr_t)data, &arg,
5971708Sstevel 		    sizeof (sckm_ioctl_status_t), flag)) {
5981708Sstevel 			cmn_err(CE_WARN, "sckm_ioctl: ddi_copyin failed");
5991708Sstevel 			return (EFAULT);
6001708Sstevel 		}
6011708Sstevel 		SCKM_DEBUG3(D_IOCTL, "sckm_ioctl: arg transid=0x%lx, "
6021708Sstevel 		    "status=%d, sadb_msg_errno=%d", arg.transid, arg.status,
6031708Sstevel 		    arg.sadb_msg_errno);
6041708Sstevel 
6051708Sstevel 		mutex_enter(&sckm_umutex);
6061708Sstevel 
6071708Sstevel 		/* fail if no status is expected, or if it does not match */
6081708Sstevel 		if (!sckm_udata_req || sckm_udata.transid != arg.transid) {
6091708Sstevel 			mutex_exit(&sckm_umutex);
6101708Sstevel 			return (EINVAL);
6111708Sstevel 		}
6121708Sstevel 
6131708Sstevel 		/* update status information for event handler */
6141708Sstevel 		bcopy(&arg, &sckm_udata_status, sizeof (sckm_ioctl_status_t));
6151708Sstevel 
6161708Sstevel 		/* signal event handler that request has been processed */
6171708Sstevel 		SCKM_DEBUG0(D_IOCTL, "sckm_ioctl: signaling event handler"
6181708Sstevel 		    " that data has been processed");
6191708Sstevel 		cv_signal(&sckm_cons_cv);
6201708Sstevel 		sckm_udata_req = B_FALSE;
6211708Sstevel 
6221708Sstevel 		mutex_exit(&sckm_umutex);
6231708Sstevel 		break;
6241708Sstevel 	}
6251708Sstevel 	default:
6261708Sstevel 		SCKM_DEBUG0(D_IOCTL, "sckm_ioctl: unknown command");
6271708Sstevel 		rval = EINVAL;
6281708Sstevel 	}
6291708Sstevel 
6301708Sstevel 	SCKM_DEBUG1(D_IOCTL, "out sckm_ioctl, rval=%d", rval);
6311708Sstevel 	return (rval);
6321708Sstevel }
6331708Sstevel 
6341708Sstevel 
6351708Sstevel /*
6361708Sstevel  * sckm_mbox_callback
6371708Sstevel  *
6381708Sstevel  * Callback routine registered with the IOSRAM mailbox protocol driver.
6391708Sstevel  * Invoked when a message is received on the mailbox.
6401708Sstevel  */
6411708Sstevel static void
sckm_mbox_callback(void)6421708Sstevel sckm_mbox_callback(void)
6431708Sstevel {
6441708Sstevel 	SCKM_DEBUG0(D_CALLBACK, "in sckm_mbox_callback()");
6451708Sstevel 
6461708Sstevel 	mutex_enter(&sckm_taskq_ptr_mutex);
6471708Sstevel 
6481708Sstevel 	if (sckm_taskq == NULL) {
6491708Sstevel 		mutex_exit(&sckm_taskq_ptr_mutex);
6501708Sstevel 		return;
6511708Sstevel 	}
6521708Sstevel 
6531708Sstevel 	if (!taskq_dispatch(sckm_taskq, sckm_mbox_task, NULL, KM_NOSLEEP)) {
6541708Sstevel 		/*
6551708Sstevel 		 * Too many tasks already pending. Do not queue a new
6561708Sstevel 		 * request.
6571708Sstevel 		 */
6581708Sstevel 		SCKM_DEBUG0(D_CALLBACK, "failed dispatching task");
6591708Sstevel 	}
6601708Sstevel 
6611708Sstevel 	mutex_exit(&sckm_taskq_ptr_mutex);
6621708Sstevel 
6631708Sstevel 	SCKM_DEBUG0(D_CALLBACK, "out sckm_mbox_callback()");
6641708Sstevel }
6651708Sstevel 
6661708Sstevel 
6671708Sstevel /*
6681708Sstevel  * sckm_mbox_task
6691708Sstevel  *
6701708Sstevel  * Dispatched on taskq from the IOSRAM mailbox callback
6711708Sstevel  * sckm_mbox_callback when a message is received on the incoming
6721708Sstevel  * mailbox.
6731708Sstevel  */
6741708Sstevel static void
sckm_mbox_task(void * ignored)6751708Sstevel sckm_mbox_task(void *ignored)
6761708Sstevel {
6771708Sstevel         _NOTE(ARGUNUSED(ignored))
6781708Sstevel 	uint32_t type, cmd, length;
6791708Sstevel 	uint64_t transid;
6801708Sstevel 	int rval;
6811708Sstevel 
6821708Sstevel 	SCKM_DEBUG0(D_TASK, "in sckm_mbox_task\n");
6831708Sstevel 
6841708Sstevel 	mutex_enter(&sckm_task_mutex);
6851708Sstevel 
6861708Sstevel 	if (req_data == NULL || rep_data == NULL) {
6871708Sstevel 		SCKM_DEBUG0(D_TASK, "sckm_mbox_task: no buffers");
6881708Sstevel 		mutex_exit(&sckm_task_mutex);
6891708Sstevel 		return;
6901708Sstevel 	}
6911708Sstevel 
6921708Sstevel 	/*
6931708Sstevel 	 * Get mailbox message.
6941708Sstevel 	 */
6951708Sstevel 
6961708Sstevel 	type = MBOXSC_MSG_REQUEST;
6971708Sstevel 	length = SCKM_SCKD_MAXDATA;
6981708Sstevel 	cmd = 0;
6991708Sstevel 	transid = 0;
7001708Sstevel 
7011708Sstevel 	SCKM_DEBUG0(D_TASK, "sckm_mbox_task: "
7021708Sstevel 	    "calling mboxsc_getmsg()\n");
7031708Sstevel 	rval = mboxsc_getmsg(KEY_SCKD, &type, &cmd, &transid,
7041708Sstevel 	    &length, req_data, sckm_getmsg_timeout);
7051708Sstevel 
7061708Sstevel 	if (rval != 0) {
7071708Sstevel 		SCKM_DEBUG1(D_TASK, "sckm_mbox_task: "
7081708Sstevel 		    "mboxsc_getmsg() failed (%d)\n", rval);
7091708Sstevel 		mutex_exit(&sckm_task_mutex);
7101708Sstevel 		return;
7111708Sstevel 	}
7121708Sstevel 
7131708Sstevel 	SCKM_DEBUG4(D_TASK, "sckm_mbox_task: "
7141708Sstevel 	    "type=0x%x cmd=0x%x length=%d transid=0x%lx\n",
7151708Sstevel 	    type, cmd, length, transid);
7161708Sstevel 
7171708Sstevel 	/* check message length */
7181708Sstevel 	if (length < sizeof (sckm_mbox_req_hdr_t)) {
7191708Sstevel 		/* protocol error, drop message */
7201708Sstevel 		SCKM_DEBUG2(D_TASK, "received short "
7211708Sstevel 		    "message of length %d, min %lu",
7221708Sstevel 		    length, sizeof (sckm_mbox_req_hdr_t));
7231708Sstevel 		mutex_exit(&sckm_task_mutex);
7241708Sstevel 		return;
7251708Sstevel 	}
7261708Sstevel 
7271708Sstevel 	/* check version of message received */
7281708Sstevel 	if (req_data->sckm_version != SCKM_PROTOCOL_VERSION) {
7291708Sstevel 		SCKM_DEBUG2(D_TASK, "received protocol "
7301708Sstevel 		    "version %d, expected %d",
7311708Sstevel 		    req_data->sckm_version, SCKM_PROTOCOL_VERSION);
7321708Sstevel 		/*
7331708Sstevel 		 * Send reply with SCKM_SADB_ERR_VERSION error
7341708Sstevel 		 * so that SC can adopt correct protocol version
7351708Sstevel 		 * for this domain.
7361708Sstevel 		 */
7371708Sstevel 		rep_data->sckm_version = SCKM_PROTOCOL_VERSION;
7381708Sstevel 		rep_data->status = SCKM_ERR_VERSION;
7391708Sstevel 
7401708Sstevel 		rval = mboxsc_putmsg(KEY_KDSC, MBOXSC_MSG_REPLY,
7411708Sstevel 		    cmd, &transid, sizeof (sckm_mbox_rep_hdr_t),
7421708Sstevel 		    rep_data, MBOXSC_PUTMSG_DEF_TIMEOUT);
7431708Sstevel 
7441708Sstevel 		if (rval != 0) {
7451708Sstevel 			SCKM_DEBUG1(D_TASK, "sckm_mbox_task: "
7461708Sstevel 			    "mboxsc_putmsg() failed (%d)\n", rval);
7471708Sstevel 			mutex_exit(&sckm_task_mutex);
7481708Sstevel 			return;
7491708Sstevel 		}
7501708Sstevel 	}
7511708Sstevel 
7521708Sstevel 	/* process message */
7531708Sstevel 	sckm_process_msg(cmd, transid, length,
7541708Sstevel 	    req_data, rep_data);
7551708Sstevel 
7561708Sstevel 	mutex_exit(&sckm_task_mutex);
7571708Sstevel }
7581708Sstevel 
7591708Sstevel /*
7601708Sstevel  * sckm_process_msg
7611708Sstevel  *
7621708Sstevel  * Process a message received from the SC. Invoked by sckm_event_task().
7631708Sstevel  */
7641708Sstevel static void
sckm_process_msg(uint32_t cmd,uint64_t transid,uint32_t len,sckm_mbox_req_hdr_t * req_data,sckm_mbox_rep_hdr_t * rep_data)7651708Sstevel sckm_process_msg(uint32_t cmd, uint64_t transid,
7661708Sstevel     uint32_t len, sckm_mbox_req_hdr_t *req_data,
7671708Sstevel     sckm_mbox_rep_hdr_t *rep_data)
7681708Sstevel {
7691708Sstevel 	int rv;
7701708Sstevel 
7711708Sstevel 	mutex_enter(&sckm_umutex);
7721708Sstevel 
7731708Sstevel 	switch (cmd) {
7741708Sstevel 	case SCKM_MSG_SADB: {
7751708Sstevel 		int sadb_msglen;
7761708Sstevel 
7771708Sstevel 		sadb_msglen = len-sizeof (sckm_mbox_req_hdr_t);
7781708Sstevel 		SCKM_DEBUG1(D_TASK, "received SCKM_MSG_SADB len=%d",
7791708Sstevel 		    sadb_msglen);
7801708Sstevel 
7811708Sstevel 		/* sanity check request */
7821708Sstevel 		if (len-sizeof (sckm_mbox_req_hdr_t) <= 0) {
7831708Sstevel 			SCKM_DEBUG0(D_TASK, "bad SADB message, "
7841708Sstevel 			    "zero length");
7851708Sstevel 			/*
7861708Sstevel 			 * SADB message is too short, send corresponding
7871708Sstevel 			 * error message to SC.
7881708Sstevel 			 */
7891708Sstevel 			rep_data->sckm_version = SCKM_PROTOCOL_VERSION;
7901708Sstevel 			rep_data->status = SCKM_ERR_SADB_MSG;
7911708Sstevel 
7921708Sstevel 			if ((rv = mboxsc_putmsg(KEY_KDSC, MBOXSC_MSG_REPLY,
7931708Sstevel 			    cmd, &transid, sizeof (sckm_mbox_rep_hdr_t),
7941708Sstevel 			    rep_data, MBOXSC_PUTMSG_DEF_TIMEOUT)) != 0) {
7951708Sstevel 				SCKM_DEBUG1(D_TASK, "sckm_mbox_task: "
7961708Sstevel 				    "mboxsc_putmsg() failed (%d)\n", rv);
7971708Sstevel 			}
7981708Sstevel 			mutex_exit(&sckm_umutex);
7991708Sstevel 			return;
8001708Sstevel 		}
8011708Sstevel 
8021708Sstevel 		/* initialize request for daemon */
8031708Sstevel 		sckm_udata.transid = transid;
8041708Sstevel 		sckm_udata.type = SCKM_IOCTL_REQ_SADB;
8051708Sstevel 		sckm_udata.buf_len = len-sizeof (sckm_mbox_req_hdr_t);
8061708Sstevel 		bcopy(req_data+1, sckm_udata.buf, sckm_udata.buf_len);
8071708Sstevel 
8081708Sstevel 		break;
8091708Sstevel 	}
8101708Sstevel 	default:
8111708Sstevel 		cmn_err(CE_WARN, "unknown cmd %x received from SC", cmd);
8121708Sstevel 		/*
8131708Sstevel 		 * Received unknown command from SC. Send corresponding
8141708Sstevel 		 * error message to SC.
8151708Sstevel 		 */
8161708Sstevel 		rep_data->sckm_version = SCKM_PROTOCOL_VERSION;
8171708Sstevel 		rep_data->status = SCKM_ERR_BAD_CMD;
8181708Sstevel 
8191708Sstevel 		if ((rv = mboxsc_putmsg(KEY_KDSC, MBOXSC_MSG_REPLY,
8201708Sstevel 		    cmd, &transid, sizeof (sckm_mbox_rep_hdr_t),
8211708Sstevel 		    rep_data, MBOXSC_PUTMSG_DEF_TIMEOUT)) != 0) {
8221708Sstevel 			SCKM_DEBUG1(D_TASK, "sckm_mbox_task: "
8231708Sstevel 			    "mboxsc_putmsg() failed (%d)\n", rv);
8241708Sstevel 		}
8251708Sstevel 		mutex_exit(&sckm_umutex);
8261708Sstevel 		return;
8271708Sstevel 	}
8281708Sstevel 
8291708Sstevel 	/*
8301708Sstevel 	 * At this point, we know that the request is valid, so pass
8311708Sstevel 	 * the request to the daemon.
8321708Sstevel 	 */
8331708Sstevel 	SCKM_DEBUG0(D_TASK, "waking up daemon");
8341708Sstevel 	sckm_udata_req = B_TRUE;
8351708Sstevel 	cv_signal(&sckm_udata_cv);
8361708Sstevel 
8371708Sstevel 	/* wait for daemon to process request */
83811066Srafael.vanoni@sun.com 	if (cv_reltimedwait(&sckm_cons_cv, &sckm_umutex,
83911066Srafael.vanoni@sun.com 	    drv_usectohz(SCKM_DAEMON_TIMEOUT), TR_CLOCK_TICK) == -1) {
8401708Sstevel 		/*
8411708Sstevel 		 * Daemon did not process the data, report this
8421708Sstevel 		 * error to the SC.
8431708Sstevel 		 */
8441708Sstevel 		SCKM_DEBUG0(D_TASK, "daemon timeout!!");
8451708Sstevel 		rep_data->sckm_version = SCKM_PROTOCOL_VERSION;
8461708Sstevel 		rep_data->status = SCKM_ERR_DAEMON;
8471708Sstevel 	} else {
8481708Sstevel 		/* Daemon processed data, return status to SC */
8491708Sstevel 		SCKM_DEBUG0(D_TASK, "daemon processed data");
8501708Sstevel 		rep_data->sckm_version = SCKM_PROTOCOL_VERSION;
8511708Sstevel 		switch (sckm_udata_status.status) {
8521708Sstevel 		case SCKM_IOCTL_STAT_SUCCESS:
8531708Sstevel 			SCKM_DEBUG0(D_TASK, "daemon returned success");
8541708Sstevel 			rep_data->status = SCKM_SUCCESS;
8551708Sstevel 			break;
8561708Sstevel 		case SCKM_IOCTL_STAT_ERR_PFKEY:
8571708Sstevel 			SCKM_DEBUG1(D_TASK, "daemon returned PF_KEY "
8581708Sstevel 			    "error, errno=%d",
8591708Sstevel 			    sckm_udata_status.sadb_msg_errno);
8601708Sstevel 			rep_data->status = SCKM_ERR_SADB_PFKEY;
8611708Sstevel 			rep_data->sadb_msg_errno =
8621708Sstevel 			    sckm_udata_status.sadb_msg_errno;
8631708Sstevel 			break;
8641708Sstevel 		case SCKM_IOCTL_STAT_ERR_REQ:
8651708Sstevel 			SCKM_DEBUG0(D_TASK, "daemon returned "
8661708Sstevel 			    "bad request");
8671708Sstevel 			rep_data->status = SCKM_ERR_DAEMON;
8681708Sstevel 			break;
8691708Sstevel 		case SCKM_IOCTL_STAT_ERR_VERSION:
8701708Sstevel 			SCKM_DEBUG0(D_TASK, "PF_KEY version not "
8711708Sstevel 			    "supported");
8721708Sstevel 			rep_data->status = SCKM_ERR_SADB_VERSION;
8731708Sstevel 			rep_data->sadb_msg_version =
8741708Sstevel 			    sckm_udata_status.sadb_msg_version;
8751708Sstevel 			break;
8761708Sstevel 		case SCKM_IOCTL_STAT_ERR_TIMEOUT:
8771708Sstevel 			SCKM_DEBUG0(D_TASK, "no response received "
8781708Sstevel 			    "from key engine");
8791708Sstevel 			rep_data->status = SCKM_ERR_SADB_TIMEOUT;
8801708Sstevel 			break;
8811708Sstevel 		case SCKM_IOCTL_STAT_ERR_OTHER:
8821708Sstevel 			SCKM_DEBUG0(D_TASK, "daemon encountered "
8831708Sstevel 			    "an error");
8841708Sstevel 			rep_data->status = SCKM_ERR_DAEMON;
8851708Sstevel 			break;
8861708Sstevel 		case SCKM_IOCTL_STAT_ERR_SADB_TYPE:
8871708Sstevel 			SCKM_DEBUG0(D_TASK, "daemon returned bad "
8881708Sstevel 			    "SADB message type");
8891708Sstevel 			rep_data->status = SCKM_ERR_SADB_BAD_TYPE;
8901708Sstevel 			break;
8911708Sstevel 		default:
8921708Sstevel 			cmn_err(CE_WARN, "SCKM daemon returned "
8931708Sstevel 			    "invalid status %d", sckm_udata_status.status);
8941708Sstevel 			rep_data->status = SCKM_ERR_DAEMON;
8951708Sstevel 		}
8961708Sstevel 	}
8971708Sstevel 
8981708Sstevel 	/* send reply back to SC */
8991708Sstevel 	if ((rv = mboxsc_putmsg(KEY_KDSC, MBOXSC_MSG_REPLY,
9001708Sstevel 	    cmd, &transid, sizeof (sckm_mbox_rep_hdr_t),
9011708Sstevel 	    rep_data, MBOXSC_PUTMSG_DEF_TIMEOUT)) != 0) {
9021708Sstevel 		SCKM_DEBUG1(D_TASK, "failed sending reply to SC (%d)", rv);
9031708Sstevel 	} else {
9041708Sstevel 		SCKM_DEBUG0(D_TASK, "reply sent to SC");
9051708Sstevel 	}
9061708Sstevel 
9071708Sstevel 	sckm_udata_req = B_FALSE;
9081708Sstevel 	mutex_exit(&sckm_umutex);
9091708Sstevel }
910