xref: /onnv-gate/usr/src/uts/common/fs/smbsrv/smb_kdoor.c (revision 12890:16985853e3aa)
111963SAfshin.Ardakani@Sun.COM /*
211963SAfshin.Ardakani@Sun.COM  * CDDL HEADER START
311963SAfshin.Ardakani@Sun.COM  *
411963SAfshin.Ardakani@Sun.COM  * The contents of this file are subject to the terms of the
511963SAfshin.Ardakani@Sun.COM  * Common Development and Distribution License (the "License").
611963SAfshin.Ardakani@Sun.COM  * You may not use this file except in compliance with the License.
711963SAfshin.Ardakani@Sun.COM  *
811963SAfshin.Ardakani@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
911963SAfshin.Ardakani@Sun.COM  * or http://www.opensolaris.org/os/licensing.
1011963SAfshin.Ardakani@Sun.COM  * See the License for the specific language governing permissions
1111963SAfshin.Ardakani@Sun.COM  * and limitations under the License.
1211963SAfshin.Ardakani@Sun.COM  *
1311963SAfshin.Ardakani@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
1411963SAfshin.Ardakani@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1511963SAfshin.Ardakani@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
1611963SAfshin.Ardakani@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
1711963SAfshin.Ardakani@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
1811963SAfshin.Ardakani@Sun.COM  *
1911963SAfshin.Ardakani@Sun.COM  * CDDL HEADER END
2011963SAfshin.Ardakani@Sun.COM  */
2111963SAfshin.Ardakani@Sun.COM /*
22*12890SJoyce.McIntosh@Sun.COM  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
2311963SAfshin.Ardakani@Sun.COM  */
2411963SAfshin.Ardakani@Sun.COM 
2511963SAfshin.Ardakani@Sun.COM #include <sys/types.h>
2611963SAfshin.Ardakani@Sun.COM #include <sys/kmem.h>
2711963SAfshin.Ardakani@Sun.COM #include <sys/ddi.h>
2811963SAfshin.Ardakani@Sun.COM #include <sys/sunddi.h>
2911963SAfshin.Ardakani@Sun.COM #include <sys/cmn_err.h>
3011963SAfshin.Ardakani@Sun.COM #include <sys/door.h>
3111963SAfshin.Ardakani@Sun.COM #include <smbsrv/smb_kproto.h>
3211963SAfshin.Ardakani@Sun.COM #include <smbsrv/smb_door.h>
3311963SAfshin.Ardakani@Sun.COM 
3411963SAfshin.Ardakani@Sun.COM static int smb_kdoor_send(smb_doorarg_t *);
3511963SAfshin.Ardakani@Sun.COM static int smb_kdoor_receive(smb_doorarg_t *);
3611963SAfshin.Ardakani@Sun.COM static int smb_kdoor_upcall_private(smb_doorarg_t *);
3711963SAfshin.Ardakani@Sun.COM static int smb_kdoor_encode(smb_doorarg_t *);
3811963SAfshin.Ardakani@Sun.COM static int smb_kdoor_decode(smb_doorarg_t *);
3911963SAfshin.Ardakani@Sun.COM static void smb_kdoor_sethdr(smb_doorarg_t *, uint32_t);
4011963SAfshin.Ardakani@Sun.COM static boolean_t smb_kdoor_chkhdr(smb_doorarg_t *, smb_doorhdr_t *);
4111963SAfshin.Ardakani@Sun.COM static void smb_kdoor_free(door_arg_t *);
4211963SAfshin.Ardakani@Sun.COM 
4311963SAfshin.Ardakani@Sun.COM door_handle_t smb_kdoor_hd = NULL;
4411963SAfshin.Ardakani@Sun.COM static int smb_kdoor_id = -1;
4511963SAfshin.Ardakani@Sun.COM static uint64_t smb_kdoor_ncall = 0;
4611963SAfshin.Ardakani@Sun.COM static kmutex_t smb_kdoor_mutex;
4711963SAfshin.Ardakani@Sun.COM static kcondvar_t smb_kdoor_cv;
4811963SAfshin.Ardakani@Sun.COM 
4911963SAfshin.Ardakani@Sun.COM void
smb_kdoor_init(void)5011963SAfshin.Ardakani@Sun.COM smb_kdoor_init(void)
5111963SAfshin.Ardakani@Sun.COM {
5211963SAfshin.Ardakani@Sun.COM 	mutex_init(&smb_kdoor_mutex, NULL, MUTEX_DEFAULT, NULL);
5311963SAfshin.Ardakani@Sun.COM 	cv_init(&smb_kdoor_cv, NULL, CV_DEFAULT, NULL);
5411963SAfshin.Ardakani@Sun.COM }
5511963SAfshin.Ardakani@Sun.COM 
5611963SAfshin.Ardakani@Sun.COM void
smb_kdoor_fini(void)5711963SAfshin.Ardakani@Sun.COM smb_kdoor_fini(void)
5811963SAfshin.Ardakani@Sun.COM {
5911963SAfshin.Ardakani@Sun.COM 	smb_kdoor_close();
6011963SAfshin.Ardakani@Sun.COM 	cv_destroy(&smb_kdoor_cv);
6111963SAfshin.Ardakani@Sun.COM 	mutex_destroy(&smb_kdoor_mutex);
6211963SAfshin.Ardakani@Sun.COM }
6311963SAfshin.Ardakani@Sun.COM 
6411963SAfshin.Ardakani@Sun.COM /*
6511963SAfshin.Ardakani@Sun.COM  * Open the door.  If the door is already open, close it first
6611963SAfshin.Ardakani@Sun.COM  * because the door-id has probably changed.
6711963SAfshin.Ardakani@Sun.COM  */
6811963SAfshin.Ardakani@Sun.COM int
smb_kdoor_open(int door_id)6911963SAfshin.Ardakani@Sun.COM smb_kdoor_open(int door_id)
7011963SAfshin.Ardakani@Sun.COM {
7111963SAfshin.Ardakani@Sun.COM 	int rc;
7211963SAfshin.Ardakani@Sun.COM 
7311963SAfshin.Ardakani@Sun.COM 	smb_kdoor_close();
7411963SAfshin.Ardakani@Sun.COM 
7511963SAfshin.Ardakani@Sun.COM 	mutex_enter(&smb_kdoor_mutex);
7611963SAfshin.Ardakani@Sun.COM 	smb_kdoor_ncall = 0;
7711963SAfshin.Ardakani@Sun.COM 
7811963SAfshin.Ardakani@Sun.COM 	if (smb_kdoor_hd == NULL) {
7911963SAfshin.Ardakani@Sun.COM 		smb_kdoor_id = door_id;
8011963SAfshin.Ardakani@Sun.COM 		smb_kdoor_hd = door_ki_lookup(door_id);
8111963SAfshin.Ardakani@Sun.COM 	}
8211963SAfshin.Ardakani@Sun.COM 
8311963SAfshin.Ardakani@Sun.COM 	rc = (smb_kdoor_hd == NULL)  ? -1 : 0;
8411963SAfshin.Ardakani@Sun.COM 	mutex_exit(&smb_kdoor_mutex);
8511963SAfshin.Ardakani@Sun.COM 	return (rc);
8611963SAfshin.Ardakani@Sun.COM }
8711963SAfshin.Ardakani@Sun.COM 
8811963SAfshin.Ardakani@Sun.COM /*
8911963SAfshin.Ardakani@Sun.COM  * Close the door.
9011963SAfshin.Ardakani@Sun.COM  */
9111963SAfshin.Ardakani@Sun.COM void
smb_kdoor_close(void)9211963SAfshin.Ardakani@Sun.COM smb_kdoor_close(void)
9311963SAfshin.Ardakani@Sun.COM {
9411963SAfshin.Ardakani@Sun.COM 	mutex_enter(&smb_kdoor_mutex);
9511963SAfshin.Ardakani@Sun.COM 
9611963SAfshin.Ardakani@Sun.COM 	if (smb_kdoor_hd != NULL) {
9711963SAfshin.Ardakani@Sun.COM 		while (smb_kdoor_ncall > 0)
9811963SAfshin.Ardakani@Sun.COM 			cv_wait(&smb_kdoor_cv, &smb_kdoor_mutex);
9911963SAfshin.Ardakani@Sun.COM 
10011963SAfshin.Ardakani@Sun.COM 		door_ki_rele(smb_kdoor_hd);
10111963SAfshin.Ardakani@Sun.COM 		smb_kdoor_hd = NULL;
10211963SAfshin.Ardakani@Sun.COM 	}
10311963SAfshin.Ardakani@Sun.COM 
10411963SAfshin.Ardakani@Sun.COM 	mutex_exit(&smb_kdoor_mutex);
10511963SAfshin.Ardakani@Sun.COM }
10611963SAfshin.Ardakani@Sun.COM 
10711963SAfshin.Ardakani@Sun.COM /*
10811963SAfshin.Ardakani@Sun.COM  * Wrapper to handle door call reference counting.
10911963SAfshin.Ardakani@Sun.COM  */
11011963SAfshin.Ardakani@Sun.COM int
smb_kdoor_upcall(uint32_t cmd,void * req_data,xdrproc_t req_xdr,void * rsp_data,xdrproc_t rsp_xdr)11111963SAfshin.Ardakani@Sun.COM smb_kdoor_upcall(uint32_t cmd, void *req_data, xdrproc_t req_xdr,
11211963SAfshin.Ardakani@Sun.COM     void *rsp_data, xdrproc_t rsp_xdr)
11311963SAfshin.Ardakani@Sun.COM {
11411963SAfshin.Ardakani@Sun.COM 	smb_doorarg_t	da;
11511963SAfshin.Ardakani@Sun.COM 	int		rc;
11611963SAfshin.Ardakani@Sun.COM 
11711963SAfshin.Ardakani@Sun.COM 	bzero(&da, sizeof (smb_doorarg_t));
11811963SAfshin.Ardakani@Sun.COM 	da.da_opcode = cmd;
11911963SAfshin.Ardakani@Sun.COM 	da.da_opname = smb_doorhdr_opname(cmd);
12011963SAfshin.Ardakani@Sun.COM 	da.da_req_xdr = req_xdr;
12111963SAfshin.Ardakani@Sun.COM 	da.da_rsp_xdr = rsp_xdr;
12211963SAfshin.Ardakani@Sun.COM 	da.da_req_data = req_data;
12311963SAfshin.Ardakani@Sun.COM 	da.da_rsp_data = rsp_data;
12411963SAfshin.Ardakani@Sun.COM 
12511963SAfshin.Ardakani@Sun.COM 	if ((req_data == NULL && req_xdr != NULL) ||
12611963SAfshin.Ardakani@Sun.COM 	    (rsp_data == NULL && rsp_xdr != NULL)) {
12711963SAfshin.Ardakani@Sun.COM 		cmn_err(CE_WARN, "smb_kdoor_upcall[%s]: invalid param",
12811963SAfshin.Ardakani@Sun.COM 		    da.da_opname);
12911963SAfshin.Ardakani@Sun.COM 		return (-1);
13011963SAfshin.Ardakani@Sun.COM 	}
13111963SAfshin.Ardakani@Sun.COM 
13211963SAfshin.Ardakani@Sun.COM 	if (rsp_data != NULL && rsp_xdr != NULL)
13311963SAfshin.Ardakani@Sun.COM 		da.da_flags = SMB_DF_ASYNC;
13411963SAfshin.Ardakani@Sun.COM 
135*12890SJoyce.McIntosh@Sun.COM 	if ((da.da_event = smb_event_create(SMB_EVENT_TIMEOUT)) == NULL)
13611963SAfshin.Ardakani@Sun.COM 		return (-1);
13711963SAfshin.Ardakani@Sun.COM 
13811963SAfshin.Ardakani@Sun.COM 	mutex_enter(&smb_kdoor_mutex);
13911963SAfshin.Ardakani@Sun.COM 
14011963SAfshin.Ardakani@Sun.COM 	if (smb_kdoor_hd == NULL) {
14111963SAfshin.Ardakani@Sun.COM 		mutex_exit(&smb_kdoor_mutex);
14211963SAfshin.Ardakani@Sun.COM 
14311963SAfshin.Ardakani@Sun.COM 		if (smb_kdoor_open(smb_kdoor_id) != 0) {
14411963SAfshin.Ardakani@Sun.COM 			smb_event_destroy(da.da_event);
14511963SAfshin.Ardakani@Sun.COM 			return (-1);
14611963SAfshin.Ardakani@Sun.COM 		}
14711963SAfshin.Ardakani@Sun.COM 
14811963SAfshin.Ardakani@Sun.COM 		mutex_enter(&smb_kdoor_mutex);
14911963SAfshin.Ardakani@Sun.COM 	}
15011963SAfshin.Ardakani@Sun.COM 
15111963SAfshin.Ardakani@Sun.COM 	++smb_kdoor_ncall;
15211963SAfshin.Ardakani@Sun.COM 	mutex_exit(&smb_kdoor_mutex);
15311963SAfshin.Ardakani@Sun.COM 
15411963SAfshin.Ardakani@Sun.COM 	if (da.da_flags & SMB_DF_ASYNC) {
15511963SAfshin.Ardakani@Sun.COM 		if ((rc = smb_kdoor_send(&da)) == 0) {
15611963SAfshin.Ardakani@Sun.COM 			if (smb_event_wait(da.da_event) != 0)
15711963SAfshin.Ardakani@Sun.COM 				rc = -1;
15811963SAfshin.Ardakani@Sun.COM 			else
15911963SAfshin.Ardakani@Sun.COM 				rc = smb_kdoor_receive(&da);
16011963SAfshin.Ardakani@Sun.COM 		}
16111963SAfshin.Ardakani@Sun.COM 	} else {
16211963SAfshin.Ardakani@Sun.COM 		if ((rc = smb_kdoor_encode(&da)) == 0) {
16311963SAfshin.Ardakani@Sun.COM 			if ((rc = smb_kdoor_upcall_private(&da)) == 0)
16411963SAfshin.Ardakani@Sun.COM 				rc = smb_kdoor_decode(&da);
16511963SAfshin.Ardakani@Sun.COM 		}
16611963SAfshin.Ardakani@Sun.COM 		smb_kdoor_free(&da.da_arg);
16711963SAfshin.Ardakani@Sun.COM 	}
16811963SAfshin.Ardakani@Sun.COM 
16911963SAfshin.Ardakani@Sun.COM 	smb_event_destroy(da.da_event);
17011963SAfshin.Ardakani@Sun.COM 
17111963SAfshin.Ardakani@Sun.COM 	mutex_enter(&smb_kdoor_mutex);
17211963SAfshin.Ardakani@Sun.COM 	if ((--smb_kdoor_ncall) == 0)
17311963SAfshin.Ardakani@Sun.COM 		cv_signal(&smb_kdoor_cv);
17411963SAfshin.Ardakani@Sun.COM 	mutex_exit(&smb_kdoor_mutex);
17511963SAfshin.Ardakani@Sun.COM 	return (rc);
17611963SAfshin.Ardakani@Sun.COM }
17711963SAfshin.Ardakani@Sun.COM 
17811963SAfshin.Ardakani@Sun.COM /*
17911963SAfshin.Ardakani@Sun.COM  * Send the request half of the consumer's door call.
18011963SAfshin.Ardakani@Sun.COM  */
18111963SAfshin.Ardakani@Sun.COM static int
smb_kdoor_send(smb_doorarg_t * outer_da)18211963SAfshin.Ardakani@Sun.COM smb_kdoor_send(smb_doorarg_t *outer_da)
18311963SAfshin.Ardakani@Sun.COM {
18411963SAfshin.Ardakani@Sun.COM 	smb_doorarg_t	da;
18511963SAfshin.Ardakani@Sun.COM 	int		rc;
18611963SAfshin.Ardakani@Sun.COM 
18711963SAfshin.Ardakani@Sun.COM 	bcopy(outer_da, &da, sizeof (smb_doorarg_t));
18811963SAfshin.Ardakani@Sun.COM 	da.da_rsp_xdr = NULL;
18911963SAfshin.Ardakani@Sun.COM 	da.da_rsp_data = NULL;
19011963SAfshin.Ardakani@Sun.COM 
19111963SAfshin.Ardakani@Sun.COM 	if (smb_kdoor_encode(&da) != 0)
19211963SAfshin.Ardakani@Sun.COM 		return (-1);
19311963SAfshin.Ardakani@Sun.COM 
19411963SAfshin.Ardakani@Sun.COM 	if ((rc = smb_kdoor_upcall_private(&da)) == 0)
19511963SAfshin.Ardakani@Sun.COM 		rc = smb_kdoor_decode(&da);
19611963SAfshin.Ardakani@Sun.COM 
19711963SAfshin.Ardakani@Sun.COM 	smb_kdoor_free(&da.da_arg);
19811963SAfshin.Ardakani@Sun.COM 	return (rc);
19911963SAfshin.Ardakani@Sun.COM }
20011963SAfshin.Ardakani@Sun.COM 
20111963SAfshin.Ardakani@Sun.COM /*
20211963SAfshin.Ardakani@Sun.COM  * Get the response half for the consumer's door call.
20311963SAfshin.Ardakani@Sun.COM  */
20411963SAfshin.Ardakani@Sun.COM static int
smb_kdoor_receive(smb_doorarg_t * outer_da)20511963SAfshin.Ardakani@Sun.COM smb_kdoor_receive(smb_doorarg_t *outer_da)
20611963SAfshin.Ardakani@Sun.COM {
20711963SAfshin.Ardakani@Sun.COM 	smb_doorarg_t	da;
20811963SAfshin.Ardakani@Sun.COM 	int		rc;
20911963SAfshin.Ardakani@Sun.COM 
21011963SAfshin.Ardakani@Sun.COM 	bcopy(outer_da, &da, sizeof (smb_doorarg_t));
21111963SAfshin.Ardakani@Sun.COM 	da.da_opcode = SMB_DR_ASYNC_RESPONSE;
21211963SAfshin.Ardakani@Sun.COM 	da.da_opname = smb_doorhdr_opname(da.da_opcode);
21311963SAfshin.Ardakani@Sun.COM 	da.da_flags &= ~SMB_DF_ASYNC;
21411963SAfshin.Ardakani@Sun.COM 	da.da_req_xdr = NULL;
21511963SAfshin.Ardakani@Sun.COM 	da.da_req_data = NULL;
21611963SAfshin.Ardakani@Sun.COM 
21711963SAfshin.Ardakani@Sun.COM 	if (smb_kdoor_encode(&da) != 0)
21811963SAfshin.Ardakani@Sun.COM 		return (-1);
21911963SAfshin.Ardakani@Sun.COM 
22011963SAfshin.Ardakani@Sun.COM 	if ((rc = smb_kdoor_upcall_private(&da)) == 0)
22111963SAfshin.Ardakani@Sun.COM 		rc = smb_kdoor_decode(&da);
22211963SAfshin.Ardakani@Sun.COM 
22311963SAfshin.Ardakani@Sun.COM 	smb_kdoor_free(&da.da_arg);
22411963SAfshin.Ardakani@Sun.COM 	return (rc);
22511963SAfshin.Ardakani@Sun.COM }
22611963SAfshin.Ardakani@Sun.COM 
22711963SAfshin.Ardakani@Sun.COM /*
22811963SAfshin.Ardakani@Sun.COM  * We use a copy of the door arg because doorfs may change data_ptr
22911963SAfshin.Ardakani@Sun.COM  * and we want to detect that when freeing the door buffers.  After
23011963SAfshin.Ardakani@Sun.COM  * this call, response data must be referenced via rbuf and rsize.
23111963SAfshin.Ardakani@Sun.COM  */
23211963SAfshin.Ardakani@Sun.COM static int
smb_kdoor_upcall_private(smb_doorarg_t * da)23311963SAfshin.Ardakani@Sun.COM smb_kdoor_upcall_private(smb_doorarg_t *da)
23411963SAfshin.Ardakani@Sun.COM {
23511963SAfshin.Ardakani@Sun.COM 	door_arg_t	door_arg;
23611963SAfshin.Ardakani@Sun.COM 	int		i;
23711963SAfshin.Ardakani@Sun.COM 	int		rc;
23811963SAfshin.Ardakani@Sun.COM 
23911963SAfshin.Ardakani@Sun.COM 	bcopy(&da->da_arg, &door_arg, sizeof (door_arg_t));
24011963SAfshin.Ardakani@Sun.COM 
24111963SAfshin.Ardakani@Sun.COM 	for (i = 0; i < SMB_DOOR_CALL_RETRIES; ++i) {
24211963SAfshin.Ardakani@Sun.COM 		if (smb_server_is_stopping())
24311963SAfshin.Ardakani@Sun.COM 			return (-1);
24411963SAfshin.Ardakani@Sun.COM 
24511963SAfshin.Ardakani@Sun.COM 		if ((rc = door_ki_upcall_limited(smb_kdoor_hd, &door_arg,
24611963SAfshin.Ardakani@Sun.COM 		    NULL, SIZE_MAX, 0)) == 0)
24711963SAfshin.Ardakani@Sun.COM 			break;
24811963SAfshin.Ardakani@Sun.COM 
24911963SAfshin.Ardakani@Sun.COM 		if (rc != EAGAIN && rc != EINTR)
25011963SAfshin.Ardakani@Sun.COM 			return (-1);
25111963SAfshin.Ardakani@Sun.COM 	}
25211963SAfshin.Ardakani@Sun.COM 
25311963SAfshin.Ardakani@Sun.COM 	if (rc != 0 || door_arg.data_size == 0 || door_arg.rsize == 0)
25411963SAfshin.Ardakani@Sun.COM 		return (-1);
25511963SAfshin.Ardakani@Sun.COM 
25611963SAfshin.Ardakani@Sun.COM 	da->da_arg.rbuf = door_arg.data_ptr;
25711963SAfshin.Ardakani@Sun.COM 	da->da_arg.rsize = door_arg.rsize;
25811963SAfshin.Ardakani@Sun.COM 	return (0);
25911963SAfshin.Ardakani@Sun.COM }
26011963SAfshin.Ardakani@Sun.COM 
26111963SAfshin.Ardakani@Sun.COM static int
smb_kdoor_encode(smb_doorarg_t * da)26211963SAfshin.Ardakani@Sun.COM smb_kdoor_encode(smb_doorarg_t *da)
26311963SAfshin.Ardakani@Sun.COM {
26411963SAfshin.Ardakani@Sun.COM 	XDR		xdrs;
26511963SAfshin.Ardakani@Sun.COM 	char		*buf;
26611963SAfshin.Ardakani@Sun.COM 	uint32_t	len;
26711963SAfshin.Ardakani@Sun.COM 
26811963SAfshin.Ardakani@Sun.COM 	len = xdr_sizeof(smb_doorhdr_xdr, &da->da_hdr);
26911963SAfshin.Ardakani@Sun.COM 	if (da->da_req_xdr != NULL)
27011963SAfshin.Ardakani@Sun.COM 		len += xdr_sizeof(da->da_req_xdr, da->da_req_data);
27111963SAfshin.Ardakani@Sun.COM 
27211963SAfshin.Ardakani@Sun.COM 	smb_kdoor_sethdr(da, len);
27311963SAfshin.Ardakani@Sun.COM 
27411963SAfshin.Ardakani@Sun.COM 	buf = kmem_zalloc(len, KM_SLEEP);
27511963SAfshin.Ardakani@Sun.COM 	xdrmem_create(&xdrs, buf, len, XDR_ENCODE);
27611963SAfshin.Ardakani@Sun.COM 
27711963SAfshin.Ardakani@Sun.COM 	if (!smb_doorhdr_xdr(&xdrs, &da->da_hdr)) {
27811963SAfshin.Ardakani@Sun.COM 		cmn_err(CE_WARN, "smb_kdoor_encode[%s]: header encode failed",
27911963SAfshin.Ardakani@Sun.COM 		    da->da_opname);
28011963SAfshin.Ardakani@Sun.COM 		kmem_free(buf, len);
28111963SAfshin.Ardakani@Sun.COM 		xdr_destroy(&xdrs);
28211963SAfshin.Ardakani@Sun.COM 		return (-1);
28311963SAfshin.Ardakani@Sun.COM 	}
28411963SAfshin.Ardakani@Sun.COM 
28511963SAfshin.Ardakani@Sun.COM 	if (da->da_req_xdr != NULL) {
28611963SAfshin.Ardakani@Sun.COM 		if (!da->da_req_xdr(&xdrs, da->da_req_data)) {
28711963SAfshin.Ardakani@Sun.COM 			cmn_err(CE_WARN, "smb_kdoor_encode[%s]: encode failed",
28811963SAfshin.Ardakani@Sun.COM 			    da->da_opname);
28911963SAfshin.Ardakani@Sun.COM 			kmem_free(buf, len);
29011963SAfshin.Ardakani@Sun.COM 			xdr_destroy(&xdrs);
29111963SAfshin.Ardakani@Sun.COM 			return (-1);
29211963SAfshin.Ardakani@Sun.COM 		}
29311963SAfshin.Ardakani@Sun.COM 	}
29411963SAfshin.Ardakani@Sun.COM 
29511963SAfshin.Ardakani@Sun.COM 	da->da_arg.data_ptr = buf;
29611963SAfshin.Ardakani@Sun.COM 	da->da_arg.data_size = len;
29711963SAfshin.Ardakani@Sun.COM 	da->da_arg.desc_ptr = NULL;
29811963SAfshin.Ardakani@Sun.COM 	da->da_arg.desc_num = 0;
29911963SAfshin.Ardakani@Sun.COM 	da->da_arg.rbuf = buf;
30011963SAfshin.Ardakani@Sun.COM 	da->da_arg.rsize = len;
30111963SAfshin.Ardakani@Sun.COM 
30211963SAfshin.Ardakani@Sun.COM 	xdr_destroy(&xdrs);
30311963SAfshin.Ardakani@Sun.COM 	return (0);
30411963SAfshin.Ardakani@Sun.COM }
30511963SAfshin.Ardakani@Sun.COM 
30611963SAfshin.Ardakani@Sun.COM /*
30711963SAfshin.Ardakani@Sun.COM  * Decode the response in rbuf and rsize.
30811963SAfshin.Ardakani@Sun.COM  */
30911963SAfshin.Ardakani@Sun.COM static int
smb_kdoor_decode(smb_doorarg_t * da)31011963SAfshin.Ardakani@Sun.COM smb_kdoor_decode(smb_doorarg_t *da)
31111963SAfshin.Ardakani@Sun.COM {
31211963SAfshin.Ardakani@Sun.COM 	XDR		xdrs;
31311963SAfshin.Ardakani@Sun.COM 	smb_doorhdr_t	hdr;
31411963SAfshin.Ardakani@Sun.COM 	char		*rbuf = da->da_arg.rbuf;
31511963SAfshin.Ardakani@Sun.COM 	uint32_t	rsize = da->da_arg.rsize;
31611963SAfshin.Ardakani@Sun.COM 
31711963SAfshin.Ardakani@Sun.COM 	if (rbuf == NULL || rsize == 0) {
31811963SAfshin.Ardakani@Sun.COM 		cmn_err(CE_WARN, "smb_kdoor_decode[%s]: invalid param",
31911963SAfshin.Ardakani@Sun.COM 		    da->da_opname);
32011963SAfshin.Ardakani@Sun.COM 		return (-1);
32111963SAfshin.Ardakani@Sun.COM 	}
32211963SAfshin.Ardakani@Sun.COM 
32311963SAfshin.Ardakani@Sun.COM 	xdrmem_create(&xdrs, rbuf, rsize, XDR_DECODE);
32411963SAfshin.Ardakani@Sun.COM 
32511963SAfshin.Ardakani@Sun.COM 	if (!smb_doorhdr_xdr(&xdrs, &hdr)) {
32611963SAfshin.Ardakani@Sun.COM 		cmn_err(CE_WARN, "smb_kdoor_decode[%s]: header decode failed",
32711963SAfshin.Ardakani@Sun.COM 		    da->da_opname);
32811963SAfshin.Ardakani@Sun.COM 		xdr_destroy(&xdrs);
32911963SAfshin.Ardakani@Sun.COM 		return (-1);
33011963SAfshin.Ardakani@Sun.COM 	}
33111963SAfshin.Ardakani@Sun.COM 
33211963SAfshin.Ardakani@Sun.COM 	if (!smb_kdoor_chkhdr(da, &hdr)) {
33311963SAfshin.Ardakani@Sun.COM 		xdr_destroy(&xdrs);
33411963SAfshin.Ardakani@Sun.COM 		return (-1);
33511963SAfshin.Ardakani@Sun.COM 	}
33611963SAfshin.Ardakani@Sun.COM 
33711963SAfshin.Ardakani@Sun.COM 	if (hdr.dh_datalen != 0 && da->da_rsp_xdr != NULL) {
33811963SAfshin.Ardakani@Sun.COM 		if (!da->da_rsp_xdr(&xdrs, da->da_rsp_data)) {
33911963SAfshin.Ardakani@Sun.COM 			cmn_err(CE_WARN, "smb_kdoor_decode[%s]: decode failed",
34011963SAfshin.Ardakani@Sun.COM 			    da->da_opname);
34111963SAfshin.Ardakani@Sun.COM 			xdr_destroy(&xdrs);
34211963SAfshin.Ardakani@Sun.COM 			return (-1);
34311963SAfshin.Ardakani@Sun.COM 		}
34411963SAfshin.Ardakani@Sun.COM 	}
34511963SAfshin.Ardakani@Sun.COM 
34611963SAfshin.Ardakani@Sun.COM 	xdr_destroy(&xdrs);
34711963SAfshin.Ardakani@Sun.COM 	return (0);
34811963SAfshin.Ardakani@Sun.COM }
34911963SAfshin.Ardakani@Sun.COM 
35011963SAfshin.Ardakani@Sun.COM static void
smb_kdoor_sethdr(smb_doorarg_t * da,uint32_t datalen)35111963SAfshin.Ardakani@Sun.COM smb_kdoor_sethdr(smb_doorarg_t *da, uint32_t datalen)
35211963SAfshin.Ardakani@Sun.COM {
35311963SAfshin.Ardakani@Sun.COM 	smb_doorhdr_t	*hdr = &da->da_hdr;
35411963SAfshin.Ardakani@Sun.COM 
35511963SAfshin.Ardakani@Sun.COM 	bzero(hdr, sizeof (smb_doorhdr_t));
35611963SAfshin.Ardakani@Sun.COM 	hdr->dh_magic = SMB_DOOR_HDR_MAGIC;
35711963SAfshin.Ardakani@Sun.COM 	hdr->dh_flags = da->da_flags | SMB_DF_SYSSPACE;
35811963SAfshin.Ardakani@Sun.COM 	hdr->dh_op = da->da_opcode;
35911963SAfshin.Ardakani@Sun.COM 	hdr->dh_txid = smb_event_txid(da->da_event);
36011963SAfshin.Ardakani@Sun.COM 	hdr->dh_datalen = datalen;
36111963SAfshin.Ardakani@Sun.COM 	hdr->dh_door_rc = SMB_DOP_NOT_CALLED;
36211963SAfshin.Ardakani@Sun.COM }
36311963SAfshin.Ardakani@Sun.COM 
36411963SAfshin.Ardakani@Sun.COM static boolean_t
smb_kdoor_chkhdr(smb_doorarg_t * da,smb_doorhdr_t * hdr)36511963SAfshin.Ardakani@Sun.COM smb_kdoor_chkhdr(smb_doorarg_t *da, smb_doorhdr_t *hdr)
36611963SAfshin.Ardakani@Sun.COM {
36711963SAfshin.Ardakani@Sun.COM 	if ((hdr->dh_magic != SMB_DOOR_HDR_MAGIC) ||
36811963SAfshin.Ardakani@Sun.COM 	    (hdr->dh_op != da->da_hdr.dh_op) ||
36911963SAfshin.Ardakani@Sun.COM 	    (hdr->dh_txid != da->da_hdr.dh_txid)) {
37011963SAfshin.Ardakani@Sun.COM 		cmn_err(CE_WARN, "smb_kdoor_chkhdr[%s]: invalid header",
37111963SAfshin.Ardakani@Sun.COM 		    da->da_opname);
37211963SAfshin.Ardakani@Sun.COM 		return (B_FALSE);
37311963SAfshin.Ardakani@Sun.COM 	}
37411963SAfshin.Ardakani@Sun.COM 
37511963SAfshin.Ardakani@Sun.COM 	if (hdr->dh_door_rc != SMB_DOP_SUCCESS) {
37611963SAfshin.Ardakani@Sun.COM 		cmn_err(CE_WARN, "smb_kdoor_chkhdr[%s]: call failed: %u",
37711963SAfshin.Ardakani@Sun.COM 		    da->da_opname, hdr->dh_door_rc);
37811963SAfshin.Ardakani@Sun.COM 		return (B_FALSE);
37911963SAfshin.Ardakani@Sun.COM 	}
38011963SAfshin.Ardakani@Sun.COM 
38111963SAfshin.Ardakani@Sun.COM 	return (B_TRUE);
38211963SAfshin.Ardakani@Sun.COM }
38311963SAfshin.Ardakani@Sun.COM 
38411963SAfshin.Ardakani@Sun.COM /*
38511963SAfshin.Ardakani@Sun.COM  * Free both the argument and result door buffers regardless of the status
38611963SAfshin.Ardakani@Sun.COM  * of the up-call.  The doorfs allocates a new buffer if the result buffer
38711963SAfshin.Ardakani@Sun.COM  * passed by the client is too small.
38811963SAfshin.Ardakani@Sun.COM  */
38911963SAfshin.Ardakani@Sun.COM static void
smb_kdoor_free(door_arg_t * arg)39011963SAfshin.Ardakani@Sun.COM smb_kdoor_free(door_arg_t *arg)
39111963SAfshin.Ardakani@Sun.COM {
39211963SAfshin.Ardakani@Sun.COM 	if (arg->rbuf != NULL && arg->rbuf != arg->data_ptr)
39311963SAfshin.Ardakani@Sun.COM 		kmem_free(arg->rbuf, arg->rsize);
39411963SAfshin.Ardakani@Sun.COM 
39511963SAfshin.Ardakani@Sun.COM 	if (arg->data_ptr != NULL)
39611963SAfshin.Ardakani@Sun.COM 		kmem_free(arg->data_ptr, arg->data_size);
39711963SAfshin.Ardakani@Sun.COM }
398