xref: /titanic_51/usr/src/uts/sun4u/starcat/io/sckmdrv.c (revision 07d06da50d310a325b457d6330165aebab1e0064)
103831d35Sstevel /*
203831d35Sstevel  * CDDL HEADER START
303831d35Sstevel  *
403831d35Sstevel  * The contents of this file are subject to the terms of the
503831d35Sstevel  * Common Development and Distribution License (the "License").
603831d35Sstevel  * You may not use this file except in compliance with the License.
703831d35Sstevel  *
803831d35Sstevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
903831d35Sstevel  * or http://www.opensolaris.org/os/licensing.
1003831d35Sstevel  * See the License for the specific language governing permissions
1103831d35Sstevel  * and limitations under the License.
1203831d35Sstevel  *
1303831d35Sstevel  * When distributing Covered Code, include this CDDL HEADER in each
1403831d35Sstevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1503831d35Sstevel  * If applicable, add the following below this CDDL HEADER, with the
1603831d35Sstevel  * fields enclosed by brackets "[]" replaced with your own identifying
1703831d35Sstevel  * information: Portions Copyright [yyyy] [name of copyright owner]
1803831d35Sstevel  *
1903831d35Sstevel  * CDDL HEADER END
2003831d35Sstevel  */
2103831d35Sstevel 
2203831d35Sstevel /*
23d3d50737SRafael Vanoni  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
2403831d35Sstevel  * Use is subject to license terms.
2503831d35Sstevel  */
2603831d35Sstevel 
2703831d35Sstevel 
2803831d35Sstevel /*
2903831d35Sstevel  * Starcat IPSec Key Management Driver.
3003831d35Sstevel  *
3103831d35Sstevel  * This driver runs on a Starcat Domain. It processes requests received
3203831d35Sstevel  * from the System Controller (SC) from IOSRAM, passes these requests
3303831d35Sstevel  * to the sckmd daemon by means of an open/close/ioctl interface, and
3403831d35Sstevel  * sends corresponding status information back to the SC.
3503831d35Sstevel  *
3603831d35Sstevel  * Requests received from the SC consist of IPsec security associations
3703831d35Sstevel  * (SAs) needed to secure the communication between SC and Domain daemons
3803831d35Sstevel  * communicating using the Management Network (MAN).
3903831d35Sstevel  */
4003831d35Sstevel 
4103831d35Sstevel #include <sys/types.h>
4203831d35Sstevel #include <sys/cmn_err.h>
4303831d35Sstevel #include <sys/kmem.h>
4403831d35Sstevel #include <sys/errno.h>
4503831d35Sstevel #include <sys/file.h>
4603831d35Sstevel #include <sys/open.h>
4703831d35Sstevel #include <sys/stat.h>
4803831d35Sstevel #include <sys/conf.h>
4903831d35Sstevel #include <sys/ddi.h>
5003831d35Sstevel #include <sys/cmn_err.h>
5103831d35Sstevel #include <sys/sunddi.h>
5203831d35Sstevel #include <sys/sunndi.h>
5303831d35Sstevel #include <sys/ddi_impldefs.h>
5403831d35Sstevel #include <sys/ndi_impldefs.h>
5503831d35Sstevel #include <sys/modctl.h>
5603831d35Sstevel #include <sys/disp.h>
5703831d35Sstevel #include <sys/async.h>
5803831d35Sstevel #include <sys/mboxsc.h>
5903831d35Sstevel #include <sys/sckm_msg.h>
6003831d35Sstevel #include <sys/sckm_io.h>
6103831d35Sstevel #include <sys/taskq.h>
6203831d35Sstevel #include <sys/note.h>
6303831d35Sstevel 
6403831d35Sstevel #ifdef DEBUG
6503831d35Sstevel static uint_t sckm_debug_flags = 0x0;
6603831d35Sstevel #define	SCKM_DEBUG0(f, s) if ((f)& sckm_debug_flags) \
6703831d35Sstevel 	cmn_err(CE_CONT, s)
6803831d35Sstevel #define	SCKM_DEBUG1(f, s, a) if ((f)& sckm_debug_flags) \
6903831d35Sstevel 	cmn_err(CE_CONT, s, a)
7003831d35Sstevel #define	SCKM_DEBUG2(f, s, a, b) if ((f)& sckm_debug_flags) \
7103831d35Sstevel 	cmn_err(CE_CONT, s, a, b)
7203831d35Sstevel #define	SCKM_DEBUG3(f, s, a, b, c) if ((f)& sckm_debug_flags) \
7303831d35Sstevel 	cmn_err(CE_CONT, s, a, b, c)
7403831d35Sstevel #define	SCKM_DEBUG4(f, s, a, b, c, d) if ((f)& sckm_debug_flags) \
7503831d35Sstevel 	cmn_err(CE_CONT, s, a, b, c, d)
7603831d35Sstevel #define	SCKM_DEBUG5(f, s, a, b, c, d, e) if ((f)& sckm_debug_flags) \
7703831d35Sstevel 	cmn_err(CE_CONT, s, a, b, c, d, e)
7803831d35Sstevel #define	SCKM_DEBUG6(f, s, a, b, c, d, e, ff) if ((f)& sckm_debug_flags) \
7903831d35Sstevel 	cmn_err(CE_CONT, s, a, b, c, d, e, ff)
8003831d35Sstevel #else
8103831d35Sstevel #define	SCKM_DEBUG0(f, s)
8203831d35Sstevel #define	SCKM_DEBUG1(f, s, a)
8303831d35Sstevel #define	SCKM_DEBUG2(f, s, a, b)
8403831d35Sstevel #define	SCKM_DEBUG3(f, s, a, b, c)
8503831d35Sstevel #define	SCKM_DEBUG4(f, s, a, b, c, d)
8603831d35Sstevel #define	SCKM_DEBUG5(f, s, a, b, c, d, e)
8703831d35Sstevel #define	SCKM_DEBUG6(f, s, a, b, c, d, e, ff)
8803831d35Sstevel #endif /* DEBUG */
8903831d35Sstevel 
9003831d35Sstevel #define	D_INIT		0x00000001	/* _init/_fini/_info */
9103831d35Sstevel #define	D_ATTACH	0x00000002	/* attach/detach */
9203831d35Sstevel #define	D_OPEN		0x00000008	/* open/close */
9303831d35Sstevel #define	D_IOCTL		0x00010000	/* ioctl */
9403831d35Sstevel #define	D_TASK		0x00100000	/* mailbox task processing */
9503831d35Sstevel #define	D_CALLBACK	0x00200000	/* mailbox callback */
9603831d35Sstevel 
9703831d35Sstevel static int sckm_open(dev_t *, int, int, struct cred *);
9803831d35Sstevel static int sckm_close(dev_t, int, int, struct cred *);
9903831d35Sstevel static int sckm_ioctl(dev_t, int, intptr_t, int, struct cred *, int *);
10003831d35Sstevel 
10103831d35Sstevel static struct cb_ops sckm_cb_ops = {
10203831d35Sstevel 	sckm_open,		/* open */
10303831d35Sstevel 	sckm_close,		/* close */
10403831d35Sstevel 	nodev,			/* strategy */
10503831d35Sstevel 	nodev,			/* print */
10603831d35Sstevel 	nodev,			/* dump */
10703831d35Sstevel 	nodev,			/* read */
10803831d35Sstevel 	nodev,			/* write */
10903831d35Sstevel 	sckm_ioctl,		/* ioctl */
11003831d35Sstevel 	nodev,			/* devmap */
11103831d35Sstevel 	nodev,			/* mmap */
11203831d35Sstevel 	nodev,			/* segmap */
11303831d35Sstevel 	nochpoll,		/* poll */
11403831d35Sstevel 	ddi_prop_op,		/* prop_op */
11503831d35Sstevel 	0,			/* streamtab  */
11603831d35Sstevel 	D_NEW | D_MP		/* Driver compatibility flag */
11703831d35Sstevel };
11803831d35Sstevel 
11903831d35Sstevel static int sckm_attach(dev_info_t *, ddi_attach_cmd_t);
12003831d35Sstevel static int sckm_detach(dev_info_t *, ddi_detach_cmd_t);
12103831d35Sstevel static int sckm_info(dev_info_t *, ddi_info_cmd_t, void *, void **);
12203831d35Sstevel 
12303831d35Sstevel static struct dev_ops sckm_ops = {
12403831d35Sstevel 	DEVO_REV,		/* devo_rev, */
12503831d35Sstevel 	0,			/* refcnt  */
12603831d35Sstevel 	sckm_info,		/* get_dev_info */
12703831d35Sstevel 	nulldev,		/* identify */
12803831d35Sstevel 	nulldev,		/* probe */
12903831d35Sstevel 	sckm_attach,		/* attach */
13003831d35Sstevel 	sckm_detach,		/* detach */
13103831d35Sstevel 	nodev,			/* reset */
13203831d35Sstevel 	&sckm_cb_ops,		/* driver operations */
13319397407SSherry Moore 	(struct bus_ops *)0,	/* no bus operations */
13419397407SSherry Moore 	NULL,			/* power */
13519397407SSherry Moore 	ddi_quiesce_not_needed,		/* quiesce */
13603831d35Sstevel };
13703831d35Sstevel 
13803831d35Sstevel static struct modldrv modldrv = {
13903831d35Sstevel 	&mod_driverops,
14019397407SSherry Moore 	"Key Management Driver",
14103831d35Sstevel 	&sckm_ops,
14203831d35Sstevel };
14303831d35Sstevel 
14403831d35Sstevel static struct modlinkage modlinkage = {
14503831d35Sstevel 	MODREV_1,
14603831d35Sstevel 	&modldrv,
14703831d35Sstevel 	NULL
14803831d35Sstevel };
14903831d35Sstevel 
15003831d35Sstevel /*
15103831d35Sstevel  * Private definitions.
15203831d35Sstevel  */
15303831d35Sstevel #define	SCKM_DEF_GETMSG_TIMEOUT 60	/* in seconds */
15403831d35Sstevel #define	SCKM_DAEMON_TIMEOUT	4000000	/* in microseconds */
15503831d35Sstevel #define	SCKM_NUM_TASKQ		2	/* # of task queue entries */
15603831d35Sstevel 
15703831d35Sstevel /*
15803831d35Sstevel  * For processing mailbox layer events.
15903831d35Sstevel  */
16003831d35Sstevel static kmutex_t sckm_task_mutex;
16103831d35Sstevel static kmutex_t sckm_taskq_ptr_mutex;
16203831d35Sstevel static clock_t sckm_getmsg_timeout = SCKM_DEF_GETMSG_TIMEOUT*1000;
16303831d35Sstevel static taskq_t *sckm_taskq = NULL;
16403831d35Sstevel static sckm_mbox_req_hdr_t *req_data = NULL;
16503831d35Sstevel static sckm_mbox_rep_hdr_t *rep_data = NULL;
16603831d35Sstevel 
16703831d35Sstevel 
16803831d35Sstevel /*
16903831d35Sstevel  * For synchronization with key management daemon.
17003831d35Sstevel  */
17103831d35Sstevel static kmutex_t sckm_umutex;
17203831d35Sstevel static kcondvar_t sckm_udata_cv;	/* daemon waits on data */
17303831d35Sstevel static kcondvar_t sckm_cons_cv;		/* wait for daemon to consume data */
17403831d35Sstevel static boolean_t sckm_udata_req = B_FALSE; /* data available for daemon */
17503831d35Sstevel static sckm_ioctl_getreq_t sckm_udata;	/* request for daemon */
17603831d35Sstevel static sckm_ioctl_status_t sckm_udata_status; /* status from daemon */
17703831d35Sstevel 
17803831d35Sstevel /*
17903831d35Sstevel  * Other misc private variables.
18003831d35Sstevel  */
18103831d35Sstevel static dev_info_t *sckm_devi = NULL;
18203831d35Sstevel static boolean_t sckm_oflag = B_FALSE;
18303831d35Sstevel 
18403831d35Sstevel /*
18503831d35Sstevel  * Private functions prototypes.
18603831d35Sstevel  */
18703831d35Sstevel static void sckm_mbox_callback(void);
18803831d35Sstevel static void sckm_mbox_task(void *arg);
18903831d35Sstevel static void sckm_process_msg(uint32_t cmd, uint64_t transid,
19003831d35Sstevel     uint32_t len, sckm_mbox_req_hdr_t *req_data,
19103831d35Sstevel     sckm_mbox_rep_hdr_t *rep_data);
19203831d35Sstevel 
19303831d35Sstevel 
19403831d35Sstevel int
19503831d35Sstevel _init(void)
19603831d35Sstevel {
19703831d35Sstevel 	mboxsc_timeout_range_t timeout_range;
19803831d35Sstevel 	int ret;
19903831d35Sstevel 
20003831d35Sstevel 	SCKM_DEBUG0(D_INIT, "in _init");
20103831d35Sstevel 
20203831d35Sstevel 	/*
20303831d35Sstevel 	 * Initialize outgoing mailbox (KDSC)
20403831d35Sstevel 	 */
20503831d35Sstevel 	if ((ret = mboxsc_init(KEY_KDSC, MBOXSC_MBOX_OUT, NULL)) != 0) {
20603831d35Sstevel 		cmn_err(CE_WARN, "failed initializing outgoing mailbox "
20703831d35Sstevel 		    "(%d)", ret);
20803831d35Sstevel 		return (ret);
20903831d35Sstevel 	}
21003831d35Sstevel 
21103831d35Sstevel 	/*
21203831d35Sstevel 	 * Initialize incoming mailbox (SCKD)
21303831d35Sstevel 	 */
21403831d35Sstevel 	if ((ret = mboxsc_init(KEY_SCKD, MBOXSC_MBOX_IN,
21503831d35Sstevel 	    sckm_mbox_callback)) != 0) {
21603831d35Sstevel 		cmn_err(CE_WARN, "failed initializing incoming mailbox "
21703831d35Sstevel 		    "(%d)\n", ret);
218*07d06da5SSurya Prakki 		(void) mboxsc_fini(KEY_KDSC);
21903831d35Sstevel 		return (ret);
22003831d35Sstevel 	}
22103831d35Sstevel 
22203831d35Sstevel 	if ((ret = mboxsc_ctrl(KEY_SCKD, MBOXSC_CMD_GETMSG_TIMEOUT_RANGE,
22303831d35Sstevel 	    (void *)&timeout_range)) != 0) {
224*07d06da5SSurya Prakki 		(void) mboxsc_fini(KEY_SCKD);
225*07d06da5SSurya Prakki 		(void) mboxsc_fini(KEY_KDSC);
22603831d35Sstevel 		return (ret);
22703831d35Sstevel 	}
22803831d35Sstevel 
22903831d35Sstevel 	if (sckm_getmsg_timeout < timeout_range.min_timeout) {
23003831d35Sstevel 		sckm_getmsg_timeout = timeout_range.min_timeout;
23103831d35Sstevel 		cmn_err(CE_WARN, "resetting getmsg timeout to %lx",
23203831d35Sstevel 		    sckm_getmsg_timeout);
23303831d35Sstevel 	}
23403831d35Sstevel 
23503831d35Sstevel 	if (sckm_getmsg_timeout > timeout_range.max_timeout) {
23603831d35Sstevel 		sckm_getmsg_timeout = timeout_range.max_timeout;
23703831d35Sstevel 		cmn_err(CE_WARN, "resetting getmsg timeout to %lx",
23803831d35Sstevel 		    sckm_getmsg_timeout);
23903831d35Sstevel 	}
24003831d35Sstevel 
24103831d35Sstevel 	if ((ret = mod_install(&modlinkage)) != 0) {
242*07d06da5SSurya Prakki 		(void) mboxsc_fini(KEY_KDSC);
243*07d06da5SSurya Prakki 		(void) mboxsc_fini(KEY_SCKD);
24403831d35Sstevel 		return (ret);
24503831d35Sstevel 	}
24603831d35Sstevel 
24703831d35Sstevel 	/*
24803831d35Sstevel 	 * Initialize variables needed for synchronization with daemon.
24903831d35Sstevel 	 */
25003831d35Sstevel 	sckm_udata.buf = kmem_alloc(SCKM_SCKD_MAXDATA, KM_SLEEP);
25103831d35Sstevel 	req_data = (sckm_mbox_req_hdr_t *)kmem_alloc(SCKM_SCKD_MAXDATA,
25203831d35Sstevel 	    KM_SLEEP);
25303831d35Sstevel 	rep_data = (sckm_mbox_rep_hdr_t *)kmem_alloc(SCKM_KDSC_MAXDATA,
25403831d35Sstevel 	    KM_SLEEP);
25503831d35Sstevel 
25603831d35Sstevel 	if ((sckm_udata.buf == NULL) || (req_data == NULL) ||
25703831d35Sstevel 	    (rep_data == NULL)) {
25803831d35Sstevel 		cmn_err(CE_WARN, "not enough memory during _init");
25903831d35Sstevel 
26003831d35Sstevel 		/* free what was successfully allocated */
26103831d35Sstevel 		if (sckm_udata.buf != NULL)
26203831d35Sstevel 			kmem_free(sckm_udata.buf, SCKM_SCKD_MAXDATA);
26303831d35Sstevel 		if (req_data != NULL)
26403831d35Sstevel 			kmem_free(req_data, SCKM_SCKD_MAXDATA);
26503831d35Sstevel 		if (rep_data != NULL)
26603831d35Sstevel 			kmem_free(rep_data, SCKM_KDSC_MAXDATA);
26703831d35Sstevel 		sckm_udata.buf = NULL;
26803831d35Sstevel 		req_data = NULL;
26903831d35Sstevel 		rep_data = NULL;
27003831d35Sstevel 
27103831d35Sstevel 		/* uninitialize mailboxes, remove module, and return error */
272*07d06da5SSurya Prakki 		(void) mboxsc_fini(KEY_KDSC);
273*07d06da5SSurya Prakki 		(void) mboxsc_fini(KEY_SCKD);
274*07d06da5SSurya Prakki 		(void) mod_remove(&modlinkage);
27503831d35Sstevel 		return (-1);
27603831d35Sstevel 	}
27703831d35Sstevel 
27803831d35Sstevel 	cv_init(&sckm_udata_cv, NULL, CV_DRIVER, NULL);
27903831d35Sstevel 	cv_init(&sckm_cons_cv, NULL, CV_DRIVER, NULL);
28003831d35Sstevel 	mutex_init(&sckm_umutex, NULL, MUTEX_DRIVER, NULL);
28103831d35Sstevel 
28203831d35Sstevel 	/*
28303831d35Sstevel 	 * Create mutex for task processing, protection of taskq
28403831d35Sstevel 	 * pointer, and create taskq.
28503831d35Sstevel 	 */
28603831d35Sstevel 	mutex_init(&sckm_task_mutex, NULL, MUTEX_DRIVER, NULL);
28703831d35Sstevel 	mutex_init(&sckm_taskq_ptr_mutex, NULL, MUTEX_DRIVER, NULL);
28803831d35Sstevel 	sckm_taskq = taskq_create("sckm_taskq", 1, minclsyspri,
28903831d35Sstevel 	    SCKM_NUM_TASKQ, SCKM_NUM_TASKQ, TASKQ_PREPOPULATE);
29003831d35Sstevel 
29103831d35Sstevel 	SCKM_DEBUG1(D_INIT, "out _init ret=%d\n", ret);
29203831d35Sstevel 	return (ret);
29303831d35Sstevel }
29403831d35Sstevel 
29503831d35Sstevel int
29603831d35Sstevel _fini(void)
29703831d35Sstevel {
29803831d35Sstevel 	int ret;
29903831d35Sstevel 
30003831d35Sstevel 	SCKM_DEBUG0(D_INIT, "in _fini");
30103831d35Sstevel 
30203831d35Sstevel 	if ((ret = mod_remove(&modlinkage)) != 0) {
30303831d35Sstevel 		return (ret);
30403831d35Sstevel 	}
30503831d35Sstevel 
30603831d35Sstevel 	/*
30703831d35Sstevel 	 * Wait for scheduled tasks to complete, then destroy task queue.
30803831d35Sstevel 	 */
30903831d35Sstevel 	mutex_enter(&sckm_taskq_ptr_mutex);
31003831d35Sstevel 	if (sckm_taskq != NULL) {
31103831d35Sstevel 		taskq_destroy(sckm_taskq);
31203831d35Sstevel 		sckm_taskq = NULL;
31303831d35Sstevel 	}
31403831d35Sstevel 	mutex_exit(&sckm_taskq_ptr_mutex);
31503831d35Sstevel 
31603831d35Sstevel 	/*
31703831d35Sstevel 	 * Terminate incoming and outgoing IOSRAM mailboxes
31803831d35Sstevel 	 */
319*07d06da5SSurya Prakki 	(void) mboxsc_fini(KEY_KDSC);
320*07d06da5SSurya Prakki 	(void) mboxsc_fini(KEY_SCKD);
32103831d35Sstevel 
32203831d35Sstevel 	/*
32303831d35Sstevel 	 * Destroy module synchronization objects and free memory
32403831d35Sstevel 	 */
32503831d35Sstevel 	mutex_destroy(&sckm_task_mutex);
32603831d35Sstevel 	mutex_destroy(&sckm_taskq_ptr_mutex);
32703831d35Sstevel 	mutex_destroy(&sckm_umutex);
32803831d35Sstevel 	cv_destroy(&sckm_cons_cv);
32903831d35Sstevel 
33003831d35Sstevel 	if (sckm_udata.buf != NULL) {
33103831d35Sstevel 		kmem_free(sckm_udata.buf, SCKM_SCKD_MAXDATA);
33203831d35Sstevel 		sckm_udata.buf = NULL;
33303831d35Sstevel 	}
33403831d35Sstevel 	if (rep_data != NULL) {
33503831d35Sstevel 		kmem_free(rep_data, SCKM_KDSC_MAXDATA);
33603831d35Sstevel 		rep_data = NULL;
33703831d35Sstevel 	}
33803831d35Sstevel 	if (req_data != NULL) {
33903831d35Sstevel 		kmem_free(req_data, SCKM_SCKD_MAXDATA);
34003831d35Sstevel 		req_data = NULL;
34103831d35Sstevel 	}
34203831d35Sstevel 
34303831d35Sstevel 	return (ret);
34403831d35Sstevel }
34503831d35Sstevel 
34603831d35Sstevel int
34703831d35Sstevel _info(struct modinfo *modinfop)
34803831d35Sstevel {
34903831d35Sstevel 	SCKM_DEBUG0(D_INIT, "in _info");
35003831d35Sstevel 	return (mod_info(&modlinkage, modinfop));
35103831d35Sstevel }
35203831d35Sstevel 
35303831d35Sstevel static int
35403831d35Sstevel sckm_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
35503831d35Sstevel {
35603831d35Sstevel 	SCKM_DEBUG1(D_ATTACH, "in sckm_attach, cmd=%d", cmd);
35703831d35Sstevel 
35803831d35Sstevel 	switch (cmd) {
35903831d35Sstevel 	case DDI_ATTACH:
36003831d35Sstevel 		SCKM_DEBUG0(D_ATTACH, "sckm_attach: DDI_ATTACH");
36103831d35Sstevel 		if (ddi_create_minor_node(devi, "sckmdrv", S_IFCHR,
36203831d35Sstevel 		    0, NULL, NULL) == DDI_FAILURE) {
36303831d35Sstevel 			cmn_err(CE_WARN, "ddi_create_minor_node failed");
36403831d35Sstevel 			ddi_remove_minor_node(devi, NULL);
36503831d35Sstevel 			return (DDI_FAILURE);
36603831d35Sstevel 		}
36703831d35Sstevel 		sckm_devi = devi;
36803831d35Sstevel 		break;
36903831d35Sstevel 	case DDI_SUSPEND:
37003831d35Sstevel 		SCKM_DEBUG0(D_ATTACH, "sckm_attach: DDI_SUSPEND");
37103831d35Sstevel 		break;
37203831d35Sstevel 	default:
37303831d35Sstevel 		cmn_err(CE_WARN, "sckm_attach: bad cmd %d\n", cmd);
37403831d35Sstevel 		return (DDI_FAILURE);
37503831d35Sstevel 	}
37603831d35Sstevel 
37703831d35Sstevel 	SCKM_DEBUG0(D_ATTACH, "out sckm_attach (DDI_SUCCESS)");
37803831d35Sstevel 	return (DDI_SUCCESS);
37903831d35Sstevel }
38003831d35Sstevel 
38103831d35Sstevel static int
38203831d35Sstevel sckm_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
38303831d35Sstevel {
38403831d35Sstevel 	SCKM_DEBUG1(D_ATTACH, "in sckm_detach, cmd=%d", cmd);
38503831d35Sstevel 
38603831d35Sstevel 	switch (cmd) {
38703831d35Sstevel 	case DDI_DETACH:
38803831d35Sstevel 		SCKM_DEBUG0(D_ATTACH, "sckm_detach: DDI_DETACH");
38903831d35Sstevel 		ddi_remove_minor_node(devi, NULL);
39003831d35Sstevel 		break;
39103831d35Sstevel 	case DDI_SUSPEND:
39203831d35Sstevel 		SCKM_DEBUG0(D_ATTACH, "sckm_detach: DDI_DETACH");
39303831d35Sstevel 		break;
39403831d35Sstevel 	default:
39503831d35Sstevel 		cmn_err(CE_WARN, "sckm_detach: bad cmd %d\n", cmd);
39603831d35Sstevel 		return (DDI_FAILURE);
39703831d35Sstevel 	}
39803831d35Sstevel 
39903831d35Sstevel 	SCKM_DEBUG0(D_ATTACH, "out sckm_detach (DDI_SUCCESS)");
40003831d35Sstevel 	return (DDI_SUCCESS);
40103831d35Sstevel }
40203831d35Sstevel 
40303831d35Sstevel /* ARGSUSED */
40403831d35Sstevel static int
40503831d35Sstevel sckm_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg,
40603831d35Sstevel     void **result)
40703831d35Sstevel {
40803831d35Sstevel 	int rv;
40903831d35Sstevel 
41003831d35Sstevel 	SCKM_DEBUG1(D_ATTACH, "in sckm_info, infocmd=%d", infocmd);
41103831d35Sstevel 
41203831d35Sstevel 	switch (infocmd) {
41303831d35Sstevel 	case DDI_INFO_DEVT2DEVINFO:
41403831d35Sstevel 		*result = (void *)sckm_devi;
41503831d35Sstevel 		rv = DDI_SUCCESS;
41603831d35Sstevel 		break;
41703831d35Sstevel 	case DDI_INFO_DEVT2INSTANCE:
41803831d35Sstevel 		*result = (void *)0;
41903831d35Sstevel 		rv = DDI_SUCCESS;
42003831d35Sstevel 		break;
42103831d35Sstevel 	default:
42203831d35Sstevel 		rv = DDI_FAILURE;
42303831d35Sstevel 	}
42403831d35Sstevel 
42503831d35Sstevel 	SCKM_DEBUG1(D_ATTACH, "out sckm_info, rv=%d", rv);
42603831d35Sstevel 	return (rv);
42703831d35Sstevel }
42803831d35Sstevel 
42903831d35Sstevel /*ARGSUSED*/
43003831d35Sstevel static int
43103831d35Sstevel sckm_open(dev_t *devp, int flag, int otyp, struct cred *cred)
43203831d35Sstevel {
43303831d35Sstevel 	SCKM_DEBUG0(D_OPEN, "in sckm_open");
43403831d35Sstevel 
43503831d35Sstevel 	/* check credentials of calling process */
43603831d35Sstevel 	if (drv_priv(cred)) {
43703831d35Sstevel 		SCKM_DEBUG0(D_OPEN, "sckm_open: attempt by non-root proc");
43803831d35Sstevel 		return (EPERM);
43903831d35Sstevel 	}
44003831d35Sstevel 
44103831d35Sstevel 	/* enforce exclusive access */
44203831d35Sstevel 	mutex_enter(&sckm_umutex);
44303831d35Sstevel 	if (sckm_oflag == B_TRUE) {
44403831d35Sstevel 		SCKM_DEBUG0(D_OPEN, "sckm_open: already open");
44503831d35Sstevel 		mutex_exit(&sckm_umutex);
44603831d35Sstevel 		return (EBUSY);
44703831d35Sstevel 	}
44803831d35Sstevel 	sckm_oflag = B_TRUE;
44903831d35Sstevel 	mutex_exit(&sckm_umutex);
45003831d35Sstevel 
45103831d35Sstevel 	SCKM_DEBUG0(D_OPEN, "sckm_open: succcess");
45203831d35Sstevel 	return (0);
45303831d35Sstevel }
45403831d35Sstevel 
45503831d35Sstevel /*ARGSUSED*/
45603831d35Sstevel static int
45703831d35Sstevel sckm_close(dev_t dev, int flag, int otyp, struct cred *cred)
45803831d35Sstevel {
45903831d35Sstevel 	SCKM_DEBUG0(D_OPEN, "in sckm_close");
46003831d35Sstevel 
46103831d35Sstevel 	mutex_enter(&sckm_umutex);
46203831d35Sstevel 	sckm_oflag = B_FALSE;
46303831d35Sstevel 	mutex_exit(&sckm_umutex);
46403831d35Sstevel 
46503831d35Sstevel 	return (0);
46603831d35Sstevel }
46703831d35Sstevel 
46803831d35Sstevel 
46903831d35Sstevel static int
47003831d35Sstevel sckm_copyin_ioctl_getreq(intptr_t userarg, sckm_ioctl_getreq_t *driverarg,
47103831d35Sstevel     int flag)
47203831d35Sstevel {
47303831d35Sstevel #ifdef _MULTI_DATAMODEL
47403831d35Sstevel 	switch (ddi_model_convert_from(flag & FMODELS)) {
47503831d35Sstevel 	case DDI_MODEL_ILP32: {
47603831d35Sstevel 		sckm_ioctl_getreq32_t driverarg32;
47703831d35Sstevel 		if (ddi_copyin((caddr_t)userarg, &driverarg32,
47803831d35Sstevel 		    sizeof (sckm_ioctl_getreq32_t), flag)) {
47903831d35Sstevel 			return (EFAULT);
48003831d35Sstevel 		}
48103831d35Sstevel 		driverarg->transid = driverarg32.transid;
48203831d35Sstevel 		driverarg->type = driverarg32.type;
48303831d35Sstevel 		driverarg->buf = (caddr_t)(uintptr_t)driverarg32.buf;
48403831d35Sstevel 		driverarg->buf_len = driverarg32.buf_len;
48503831d35Sstevel 		break;
48603831d35Sstevel 	}
48703831d35Sstevel 	case DDI_MODEL_NONE: {
48803831d35Sstevel 		if (ddi_copyin((caddr_t)userarg, &driverarg,
48903831d35Sstevel 		    sizeof (sckm_ioctl_getreq_t), flag)) {
49003831d35Sstevel 			return (EFAULT);
49103831d35Sstevel 		}
49203831d35Sstevel 		break;
49303831d35Sstevel 	}
49403831d35Sstevel 	}
49503831d35Sstevel #else /* ! _MULTI_DATAMODEL */
49603831d35Sstevel 	if (ddi_copyin((caddr_t)userarg, &driverarg,
49703831d35Sstevel 	    sizeof (sckm_ioctl_getreq_t), flag)) {
49803831d35Sstevel 		return (EFAULT);
49903831d35Sstevel 	}
50003831d35Sstevel #endif /* _MULTI_DATAMODEL */
50103831d35Sstevel 	return (0);
50203831d35Sstevel }
50303831d35Sstevel 
50403831d35Sstevel 
50503831d35Sstevel static int
50603831d35Sstevel sckm_copyout_ioctl_getreq(sckm_ioctl_getreq_t *driverarg, intptr_t userarg,
50703831d35Sstevel     int flag)
50803831d35Sstevel {
50903831d35Sstevel #ifdef _MULTI_DATAMODEL
51003831d35Sstevel 	switch (ddi_model_convert_from(flag & FMODELS)) {
51103831d35Sstevel 	case DDI_MODEL_ILP32: {
51203831d35Sstevel 		sckm_ioctl_getreq32_t driverarg32;
51303831d35Sstevel 		driverarg32.transid = driverarg->transid;
51403831d35Sstevel 		driverarg32.type = driverarg->type;
51503831d35Sstevel 		driverarg32.buf = (caddr32_t)(uintptr_t)driverarg->buf;
51603831d35Sstevel 		driverarg32.buf_len = driverarg->buf_len;
51703831d35Sstevel 		if (ddi_copyout(&driverarg32, (caddr_t)userarg,
51803831d35Sstevel 		    sizeof (sckm_ioctl_getreq32_t), flag)) {
51903831d35Sstevel 			return (EFAULT);
52003831d35Sstevel 		}
52103831d35Sstevel 		break;
52203831d35Sstevel 	}
52303831d35Sstevel 	case DDI_MODEL_NONE:
52403831d35Sstevel 		if (ddi_copyout(driverarg, (caddr_t)userarg,
52503831d35Sstevel 		    sizeof (sckm_ioctl_getreq_t), flag)) {
52603831d35Sstevel 			return (EFAULT);
52703831d35Sstevel 		}
52803831d35Sstevel 		break;
52903831d35Sstevel 	}
53003831d35Sstevel #else /* ! _MULTI_DATAMODEL */
53103831d35Sstevel 	if (ddi_copyout(driverarg, (caddr_t)userarg,
53203831d35Sstevel 	    sizeof (sckm_ioctl_getreq_t), flag)) {
53303831d35Sstevel 		return (EFAULT);
53403831d35Sstevel 	}
53503831d35Sstevel #endif /* _MULTI_DATAMODEL */
53603831d35Sstevel 	return (0);
53703831d35Sstevel }
53803831d35Sstevel 
53903831d35Sstevel 
54003831d35Sstevel /*ARGSUSED*/
54103831d35Sstevel static int
54203831d35Sstevel sckm_ioctl(dev_t dev, int cmd, intptr_t data, int flag,
54303831d35Sstevel     cred_t *cred, int *rvalp)
54403831d35Sstevel {
54503831d35Sstevel 	int rval = 0;
54603831d35Sstevel 
54703831d35Sstevel 	SCKM_DEBUG0(D_IOCTL, "in sckm_ioctl");
54803831d35Sstevel 
54903831d35Sstevel 	switch (cmd) {
55003831d35Sstevel 	case SCKM_IOCTL_GETREQ: {
55103831d35Sstevel 		sckm_ioctl_getreq_t arg;
55203831d35Sstevel 
55303831d35Sstevel 		SCKM_DEBUG0(D_IOCTL, "sckm_ioctl: got SCKM_IOCTL_GETREQ");
55403831d35Sstevel 		if (sckm_copyin_ioctl_getreq(data, &arg, flag)) {
55503831d35Sstevel 			return (EFAULT);
55603831d35Sstevel 		}
55703831d35Sstevel 
55803831d35Sstevel 		/* sanity check argument */
55903831d35Sstevel 		if (arg.buf_len < SCKM_SCKD_MAXDATA) {
56003831d35Sstevel 			SCKM_DEBUG2(D_IOCTL, "sckm_ioctl: usr buffer too "
56103831d35Sstevel 			    "small (%d < %d)", arg.buf_len, SCKM_SCKD_MAXDATA);
56203831d35Sstevel 			return (ENOSPC);
56303831d35Sstevel 		}
56403831d35Sstevel 
56503831d35Sstevel 		mutex_enter(&sckm_umutex);
56603831d35Sstevel 
56703831d35Sstevel 		/* wait for request from SC */
56803831d35Sstevel 		while (!sckm_udata_req) {
56903831d35Sstevel 			SCKM_DEBUG0(D_IOCTL, "sckm_ioctl: waiting for msg");
57003831d35Sstevel 			if (cv_wait_sig(&sckm_udata_cv, &sckm_umutex) == 0) {
57103831d35Sstevel 				mutex_exit(&sckm_umutex);
57203831d35Sstevel 				return (EINTR);
57303831d35Sstevel 			}
57403831d35Sstevel 		}
57503831d35Sstevel 		SCKM_DEBUG1(D_IOCTL, "sckm_ioctl: msg available "
57603831d35Sstevel 		    "transid = 0x%lx", sckm_udata.transid);
57703831d35Sstevel 
57803831d35Sstevel 		arg.transid = sckm_udata.transid;
57903831d35Sstevel 		arg.type = sckm_udata.type;
58003831d35Sstevel 		if (ddi_copyout(sckm_udata.buf, arg.buf,
58103831d35Sstevel 		    sckm_udata.buf_len, flag)) {
58203831d35Sstevel 			mutex_exit(&sckm_umutex);
58303831d35Sstevel 			return (EFAULT);
58403831d35Sstevel 		}
58503831d35Sstevel 		arg.buf_len = sckm_udata.buf_len;
58603831d35Sstevel 
58703831d35Sstevel 		mutex_exit(&sckm_umutex);
58803831d35Sstevel 		if (sckm_copyout_ioctl_getreq(&arg, data, flag)) {
58903831d35Sstevel 			return (EFAULT);
59003831d35Sstevel 		}
59103831d35Sstevel 		break;
59203831d35Sstevel 	}
59303831d35Sstevel 	case SCKM_IOCTL_STATUS: {
59403831d35Sstevel 		sckm_ioctl_status_t arg;
59503831d35Sstevel 		SCKM_DEBUG0(D_IOCTL, "sckm_ioctl: got SCKM_IOCTL_STATUS");
59603831d35Sstevel 		if (ddi_copyin((caddr_t)data, &arg,
59703831d35Sstevel 		    sizeof (sckm_ioctl_status_t), flag)) {
59803831d35Sstevel 			cmn_err(CE_WARN, "sckm_ioctl: ddi_copyin failed");
59903831d35Sstevel 			return (EFAULT);
60003831d35Sstevel 		}
60103831d35Sstevel 		SCKM_DEBUG3(D_IOCTL, "sckm_ioctl: arg transid=0x%lx, "
60203831d35Sstevel 		    "status=%d, sadb_msg_errno=%d", arg.transid, arg.status,
60303831d35Sstevel 		    arg.sadb_msg_errno);
60403831d35Sstevel 
60503831d35Sstevel 		mutex_enter(&sckm_umutex);
60603831d35Sstevel 
60703831d35Sstevel 		/* fail if no status is expected, or if it does not match */
60803831d35Sstevel 		if (!sckm_udata_req || sckm_udata.transid != arg.transid) {
60903831d35Sstevel 			mutex_exit(&sckm_umutex);
61003831d35Sstevel 			return (EINVAL);
61103831d35Sstevel 		}
61203831d35Sstevel 
61303831d35Sstevel 		/* update status information for event handler */
61403831d35Sstevel 		bcopy(&arg, &sckm_udata_status, sizeof (sckm_ioctl_status_t));
61503831d35Sstevel 
61603831d35Sstevel 		/* signal event handler that request has been processed */
61703831d35Sstevel 		SCKM_DEBUG0(D_IOCTL, "sckm_ioctl: signaling event handler"
61803831d35Sstevel 		    " that data has been processed");
61903831d35Sstevel 		cv_signal(&sckm_cons_cv);
62003831d35Sstevel 		sckm_udata_req = B_FALSE;
62103831d35Sstevel 
62203831d35Sstevel 		mutex_exit(&sckm_umutex);
62303831d35Sstevel 		break;
62403831d35Sstevel 	}
62503831d35Sstevel 	default:
62603831d35Sstevel 		SCKM_DEBUG0(D_IOCTL, "sckm_ioctl: unknown command");
62703831d35Sstevel 		rval = EINVAL;
62803831d35Sstevel 	}
62903831d35Sstevel 
63003831d35Sstevel 	SCKM_DEBUG1(D_IOCTL, "out sckm_ioctl, rval=%d", rval);
63103831d35Sstevel 	return (rval);
63203831d35Sstevel }
63303831d35Sstevel 
63403831d35Sstevel 
63503831d35Sstevel /*
63603831d35Sstevel  * sckm_mbox_callback
63703831d35Sstevel  *
63803831d35Sstevel  * Callback routine registered with the IOSRAM mailbox protocol driver.
63903831d35Sstevel  * Invoked when a message is received on the mailbox.
64003831d35Sstevel  */
64103831d35Sstevel static void
64203831d35Sstevel sckm_mbox_callback(void)
64303831d35Sstevel {
64403831d35Sstevel 	SCKM_DEBUG0(D_CALLBACK, "in sckm_mbox_callback()");
64503831d35Sstevel 
64603831d35Sstevel 	mutex_enter(&sckm_taskq_ptr_mutex);
64703831d35Sstevel 
64803831d35Sstevel 	if (sckm_taskq == NULL) {
64903831d35Sstevel 		mutex_exit(&sckm_taskq_ptr_mutex);
65003831d35Sstevel 		return;
65103831d35Sstevel 	}
65203831d35Sstevel 
65303831d35Sstevel 	if (!taskq_dispatch(sckm_taskq, sckm_mbox_task, NULL, KM_NOSLEEP)) {
65403831d35Sstevel 		/*
65503831d35Sstevel 		 * Too many tasks already pending. Do not queue a new
65603831d35Sstevel 		 * request.
65703831d35Sstevel 		 */
65803831d35Sstevel 		SCKM_DEBUG0(D_CALLBACK, "failed dispatching task");
65903831d35Sstevel 	}
66003831d35Sstevel 
66103831d35Sstevel 	mutex_exit(&sckm_taskq_ptr_mutex);
66203831d35Sstevel 
66303831d35Sstevel 	SCKM_DEBUG0(D_CALLBACK, "out sckm_mbox_callback()");
66403831d35Sstevel }
66503831d35Sstevel 
66603831d35Sstevel 
66703831d35Sstevel /*
66803831d35Sstevel  * sckm_mbox_task
66903831d35Sstevel  *
67003831d35Sstevel  * Dispatched on taskq from the IOSRAM mailbox callback
67103831d35Sstevel  * sckm_mbox_callback when a message is received on the incoming
67203831d35Sstevel  * mailbox.
67303831d35Sstevel  */
67403831d35Sstevel static void
67503831d35Sstevel sckm_mbox_task(void *ignored)
67603831d35Sstevel {
67703831d35Sstevel         _NOTE(ARGUNUSED(ignored))
67803831d35Sstevel 	uint32_t type, cmd, length;
67903831d35Sstevel 	uint64_t transid;
68003831d35Sstevel 	int rval;
68103831d35Sstevel 
68203831d35Sstevel 	SCKM_DEBUG0(D_TASK, "in sckm_mbox_task\n");
68303831d35Sstevel 
68403831d35Sstevel 	mutex_enter(&sckm_task_mutex);
68503831d35Sstevel 
68603831d35Sstevel 	if (req_data == NULL || rep_data == NULL) {
68703831d35Sstevel 		SCKM_DEBUG0(D_TASK, "sckm_mbox_task: no buffers");
68803831d35Sstevel 		mutex_exit(&sckm_task_mutex);
68903831d35Sstevel 		return;
69003831d35Sstevel 	}
69103831d35Sstevel 
69203831d35Sstevel 	/*
69303831d35Sstevel 	 * Get mailbox message.
69403831d35Sstevel 	 */
69503831d35Sstevel 
69603831d35Sstevel 	type = MBOXSC_MSG_REQUEST;
69703831d35Sstevel 	length = SCKM_SCKD_MAXDATA;
69803831d35Sstevel 	cmd = 0;
69903831d35Sstevel 	transid = 0;
70003831d35Sstevel 
70103831d35Sstevel 	SCKM_DEBUG0(D_TASK, "sckm_mbox_task: "
70203831d35Sstevel 	    "calling mboxsc_getmsg()\n");
70303831d35Sstevel 	rval = mboxsc_getmsg(KEY_SCKD, &type, &cmd, &transid,
70403831d35Sstevel 	    &length, req_data, sckm_getmsg_timeout);
70503831d35Sstevel 
70603831d35Sstevel 	if (rval != 0) {
70703831d35Sstevel 		SCKM_DEBUG1(D_TASK, "sckm_mbox_task: "
70803831d35Sstevel 		    "mboxsc_getmsg() failed (%d)\n", rval);
70903831d35Sstevel 		mutex_exit(&sckm_task_mutex);
71003831d35Sstevel 		return;
71103831d35Sstevel 	}
71203831d35Sstevel 
71303831d35Sstevel 	SCKM_DEBUG4(D_TASK, "sckm_mbox_task: "
71403831d35Sstevel 	    "type=0x%x cmd=0x%x length=%d transid=0x%lx\n",
71503831d35Sstevel 	    type, cmd, length, transid);
71603831d35Sstevel 
71703831d35Sstevel 	/* check message length */
71803831d35Sstevel 	if (length < sizeof (sckm_mbox_req_hdr_t)) {
71903831d35Sstevel 		/* protocol error, drop message */
72003831d35Sstevel 		SCKM_DEBUG2(D_TASK, "received short "
72103831d35Sstevel 		    "message of length %d, min %lu",
72203831d35Sstevel 		    length, sizeof (sckm_mbox_req_hdr_t));
72303831d35Sstevel 		mutex_exit(&sckm_task_mutex);
72403831d35Sstevel 		return;
72503831d35Sstevel 	}
72603831d35Sstevel 
72703831d35Sstevel 	/* check version of message received */
72803831d35Sstevel 	if (req_data->sckm_version != SCKM_PROTOCOL_VERSION) {
72903831d35Sstevel 		SCKM_DEBUG2(D_TASK, "received protocol "
73003831d35Sstevel 		    "version %d, expected %d",
73103831d35Sstevel 		    req_data->sckm_version, SCKM_PROTOCOL_VERSION);
73203831d35Sstevel 		/*
73303831d35Sstevel 		 * Send reply with SCKM_SADB_ERR_VERSION error
73403831d35Sstevel 		 * so that SC can adopt correct protocol version
73503831d35Sstevel 		 * for this domain.
73603831d35Sstevel 		 */
73703831d35Sstevel 		rep_data->sckm_version = SCKM_PROTOCOL_VERSION;
73803831d35Sstevel 		rep_data->status = SCKM_ERR_VERSION;
73903831d35Sstevel 
74003831d35Sstevel 		rval = mboxsc_putmsg(KEY_KDSC, MBOXSC_MSG_REPLY,
74103831d35Sstevel 		    cmd, &transid, sizeof (sckm_mbox_rep_hdr_t),
74203831d35Sstevel 		    rep_data, MBOXSC_PUTMSG_DEF_TIMEOUT);
74303831d35Sstevel 
74403831d35Sstevel 		if (rval != 0) {
74503831d35Sstevel 			SCKM_DEBUG1(D_TASK, "sckm_mbox_task: "
74603831d35Sstevel 			    "mboxsc_putmsg() failed (%d)\n", rval);
74703831d35Sstevel 			mutex_exit(&sckm_task_mutex);
74803831d35Sstevel 			return;
74903831d35Sstevel 		}
75003831d35Sstevel 	}
75103831d35Sstevel 
75203831d35Sstevel 	/* process message */
75303831d35Sstevel 	sckm_process_msg(cmd, transid, length,
75403831d35Sstevel 	    req_data, rep_data);
75503831d35Sstevel 
75603831d35Sstevel 	mutex_exit(&sckm_task_mutex);
75703831d35Sstevel }
75803831d35Sstevel 
75903831d35Sstevel /*
76003831d35Sstevel  * sckm_process_msg
76103831d35Sstevel  *
76203831d35Sstevel  * Process a message received from the SC. Invoked by sckm_event_task().
76303831d35Sstevel  */
76403831d35Sstevel static void
76503831d35Sstevel sckm_process_msg(uint32_t cmd, uint64_t transid,
76603831d35Sstevel     uint32_t len, sckm_mbox_req_hdr_t *req_data,
76703831d35Sstevel     sckm_mbox_rep_hdr_t *rep_data)
76803831d35Sstevel {
76903831d35Sstevel 	int rv;
77003831d35Sstevel 
77103831d35Sstevel 	mutex_enter(&sckm_umutex);
77203831d35Sstevel 
77303831d35Sstevel 	switch (cmd) {
77403831d35Sstevel 	case SCKM_MSG_SADB: {
77503831d35Sstevel 		int sadb_msglen;
77603831d35Sstevel 
77703831d35Sstevel 		sadb_msglen = len-sizeof (sckm_mbox_req_hdr_t);
77803831d35Sstevel 		SCKM_DEBUG1(D_TASK, "received SCKM_MSG_SADB len=%d",
77903831d35Sstevel 		    sadb_msglen);
78003831d35Sstevel 
78103831d35Sstevel 		/* sanity check request */
78203831d35Sstevel 		if (len-sizeof (sckm_mbox_req_hdr_t) <= 0) {
78303831d35Sstevel 			SCKM_DEBUG0(D_TASK, "bad SADB message, "
78403831d35Sstevel 			    "zero length");
78503831d35Sstevel 			/*
78603831d35Sstevel 			 * SADB message is too short, send corresponding
78703831d35Sstevel 			 * error message to SC.
78803831d35Sstevel 			 */
78903831d35Sstevel 			rep_data->sckm_version = SCKM_PROTOCOL_VERSION;
79003831d35Sstevel 			rep_data->status = SCKM_ERR_SADB_MSG;
79103831d35Sstevel 
79203831d35Sstevel 			if ((rv = mboxsc_putmsg(KEY_KDSC, MBOXSC_MSG_REPLY,
79303831d35Sstevel 			    cmd, &transid, sizeof (sckm_mbox_rep_hdr_t),
79403831d35Sstevel 			    rep_data, MBOXSC_PUTMSG_DEF_TIMEOUT)) != 0) {
79503831d35Sstevel 				SCKM_DEBUG1(D_TASK, "sckm_mbox_task: "
79603831d35Sstevel 				    "mboxsc_putmsg() failed (%d)\n", rv);
79703831d35Sstevel 			}
79803831d35Sstevel 			mutex_exit(&sckm_umutex);
79903831d35Sstevel 			return;
80003831d35Sstevel 		}
80103831d35Sstevel 
80203831d35Sstevel 		/* initialize request for daemon */
80303831d35Sstevel 		sckm_udata.transid = transid;
80403831d35Sstevel 		sckm_udata.type = SCKM_IOCTL_REQ_SADB;
80503831d35Sstevel 		sckm_udata.buf_len = len-sizeof (sckm_mbox_req_hdr_t);
80603831d35Sstevel 		bcopy(req_data+1, sckm_udata.buf, sckm_udata.buf_len);
80703831d35Sstevel 
80803831d35Sstevel 		break;
80903831d35Sstevel 	}
81003831d35Sstevel 	default:
81103831d35Sstevel 		cmn_err(CE_WARN, "unknown cmd %x received from SC", cmd);
81203831d35Sstevel 		/*
81303831d35Sstevel 		 * Received unknown command from SC. Send corresponding
81403831d35Sstevel 		 * error message to SC.
81503831d35Sstevel 		 */
81603831d35Sstevel 		rep_data->sckm_version = SCKM_PROTOCOL_VERSION;
81703831d35Sstevel 		rep_data->status = SCKM_ERR_BAD_CMD;
81803831d35Sstevel 
81903831d35Sstevel 		if ((rv = mboxsc_putmsg(KEY_KDSC, MBOXSC_MSG_REPLY,
82003831d35Sstevel 		    cmd, &transid, sizeof (sckm_mbox_rep_hdr_t),
82103831d35Sstevel 		    rep_data, MBOXSC_PUTMSG_DEF_TIMEOUT)) != 0) {
82203831d35Sstevel 			SCKM_DEBUG1(D_TASK, "sckm_mbox_task: "
82303831d35Sstevel 			    "mboxsc_putmsg() failed (%d)\n", rv);
82403831d35Sstevel 		}
82503831d35Sstevel 		mutex_exit(&sckm_umutex);
82603831d35Sstevel 		return;
82703831d35Sstevel 	}
82803831d35Sstevel 
82903831d35Sstevel 	/*
83003831d35Sstevel 	 * At this point, we know that the request is valid, so pass
83103831d35Sstevel 	 * the request to the daemon.
83203831d35Sstevel 	 */
83303831d35Sstevel 	SCKM_DEBUG0(D_TASK, "waking up daemon");
83403831d35Sstevel 	sckm_udata_req = B_TRUE;
83503831d35Sstevel 	cv_signal(&sckm_udata_cv);
83603831d35Sstevel 
83703831d35Sstevel 	/* wait for daemon to process request */
838d3d50737SRafael Vanoni 	if (cv_reltimedwait(&sckm_cons_cv, &sckm_umutex,
839d3d50737SRafael Vanoni 	    drv_usectohz(SCKM_DAEMON_TIMEOUT), TR_CLOCK_TICK) == -1) {
84003831d35Sstevel 		/*
84103831d35Sstevel 		 * Daemon did not process the data, report this
84203831d35Sstevel 		 * error to the SC.
84303831d35Sstevel 		 */
84403831d35Sstevel 		SCKM_DEBUG0(D_TASK, "daemon timeout!!");
84503831d35Sstevel 		rep_data->sckm_version = SCKM_PROTOCOL_VERSION;
84603831d35Sstevel 		rep_data->status = SCKM_ERR_DAEMON;
84703831d35Sstevel 	} else {
84803831d35Sstevel 		/* Daemon processed data, return status to SC */
84903831d35Sstevel 		SCKM_DEBUG0(D_TASK, "daemon processed data");
85003831d35Sstevel 		rep_data->sckm_version = SCKM_PROTOCOL_VERSION;
85103831d35Sstevel 		switch (sckm_udata_status.status) {
85203831d35Sstevel 		case SCKM_IOCTL_STAT_SUCCESS:
85303831d35Sstevel 			SCKM_DEBUG0(D_TASK, "daemon returned success");
85403831d35Sstevel 			rep_data->status = SCKM_SUCCESS;
85503831d35Sstevel 			break;
85603831d35Sstevel 		case SCKM_IOCTL_STAT_ERR_PFKEY:
85703831d35Sstevel 			SCKM_DEBUG1(D_TASK, "daemon returned PF_KEY "
85803831d35Sstevel 			    "error, errno=%d",
85903831d35Sstevel 			    sckm_udata_status.sadb_msg_errno);
86003831d35Sstevel 			rep_data->status = SCKM_ERR_SADB_PFKEY;
86103831d35Sstevel 			rep_data->sadb_msg_errno =
86203831d35Sstevel 			    sckm_udata_status.sadb_msg_errno;
86303831d35Sstevel 			break;
86403831d35Sstevel 		case SCKM_IOCTL_STAT_ERR_REQ:
86503831d35Sstevel 			SCKM_DEBUG0(D_TASK, "daemon returned "
86603831d35Sstevel 			    "bad request");
86703831d35Sstevel 			rep_data->status = SCKM_ERR_DAEMON;
86803831d35Sstevel 			break;
86903831d35Sstevel 		case SCKM_IOCTL_STAT_ERR_VERSION:
87003831d35Sstevel 			SCKM_DEBUG0(D_TASK, "PF_KEY version not "
87103831d35Sstevel 			    "supported");
87203831d35Sstevel 			rep_data->status = SCKM_ERR_SADB_VERSION;
87303831d35Sstevel 			rep_data->sadb_msg_version =
87403831d35Sstevel 			    sckm_udata_status.sadb_msg_version;
87503831d35Sstevel 			break;
87603831d35Sstevel 		case SCKM_IOCTL_STAT_ERR_TIMEOUT:
87703831d35Sstevel 			SCKM_DEBUG0(D_TASK, "no response received "
87803831d35Sstevel 			    "from key engine");
87903831d35Sstevel 			rep_data->status = SCKM_ERR_SADB_TIMEOUT;
88003831d35Sstevel 			break;
88103831d35Sstevel 		case SCKM_IOCTL_STAT_ERR_OTHER:
88203831d35Sstevel 			SCKM_DEBUG0(D_TASK, "daemon encountered "
88303831d35Sstevel 			    "an error");
88403831d35Sstevel 			rep_data->status = SCKM_ERR_DAEMON;
88503831d35Sstevel 			break;
88603831d35Sstevel 		case SCKM_IOCTL_STAT_ERR_SADB_TYPE:
88703831d35Sstevel 			SCKM_DEBUG0(D_TASK, "daemon returned bad "
88803831d35Sstevel 			    "SADB message type");
88903831d35Sstevel 			rep_data->status = SCKM_ERR_SADB_BAD_TYPE;
89003831d35Sstevel 			break;
89103831d35Sstevel 		default:
89203831d35Sstevel 			cmn_err(CE_WARN, "SCKM daemon returned "
89303831d35Sstevel 			    "invalid status %d", sckm_udata_status.status);
89403831d35Sstevel 			rep_data->status = SCKM_ERR_DAEMON;
89503831d35Sstevel 		}
89603831d35Sstevel 	}
89703831d35Sstevel 
89803831d35Sstevel 	/* send reply back to SC */
89903831d35Sstevel 	if ((rv = mboxsc_putmsg(KEY_KDSC, MBOXSC_MSG_REPLY,
90003831d35Sstevel 	    cmd, &transid, sizeof (sckm_mbox_rep_hdr_t),
90103831d35Sstevel 	    rep_data, MBOXSC_PUTMSG_DEF_TIMEOUT)) != 0) {
90203831d35Sstevel 		SCKM_DEBUG1(D_TASK, "failed sending reply to SC (%d)", rv);
90303831d35Sstevel 	} else {
90403831d35Sstevel 		SCKM_DEBUG0(D_TASK, "reply sent to SC");
90503831d35Sstevel 	}
90603831d35Sstevel 
90703831d35Sstevel 	sckm_udata_req = B_FALSE;
90803831d35Sstevel 	mutex_exit(&sckm_umutex);
90903831d35Sstevel }
910