xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_opipe.c (revision 9fb67ea305c66b6a297583b9b0db6796b0dfe497)
13db3f65cSamw /*
23db3f65cSamw  * CDDL HEADER START
33db3f65cSamw  *
43db3f65cSamw  * The contents of this file are subject to the terms of the
53db3f65cSamw  * Common Development and Distribution License (the "License").
63db3f65cSamw  * You may not use this file except in compliance with the License.
73db3f65cSamw  *
83db3f65cSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93db3f65cSamw  * or http://www.opensolaris.org/os/licensing.
103db3f65cSamw  * See the License for the specific language governing permissions
113db3f65cSamw  * and limitations under the License.
123db3f65cSamw  *
133db3f65cSamw  * When distributing Covered Code, include this CDDL HEADER in each
143db3f65cSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153db3f65cSamw  * If applicable, add the following below this CDDL HEADER, with the
163db3f65cSamw  * fields enclosed by brackets "[]" replaced with your own identifying
173db3f65cSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
183db3f65cSamw  *
193db3f65cSamw  * CDDL HEADER END
203db3f65cSamw  */
213db3f65cSamw /*
22*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
233db3f65cSamw  * Use is subject to license terms.
243db3f65cSamw  */
253db3f65cSamw 
263db3f65cSamw /*
273db3f65cSamw  * This module provides the interface to NDR RPC.
283db3f65cSamw  */
293db3f65cSamw 
303db3f65cSamw #include <sys/stat.h>
313db3f65cSamw #include <sys/door.h>
323db3f65cSamw #include <sys/door_data.h>
333db3f65cSamw #include <sys/uio.h>
343db3f65cSamw #include <sys/ksynch.h>
35bbf6f00cSJordan Brown #include <smbsrv/smb_kproto.h>
363db3f65cSamw #include <smbsrv/smb_xdr.h>
373db3f65cSamw 
383db3f65cSamw #define	SMB_OPIPE_ISOPEN(OPIPE)	\
39*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	(((OPIPE)->p_hdr.dh_magic == SMB_OPIPE_HDR_MAGIC) && \
40*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	((OPIPE)->p_hdr.dh_fid))
413db3f65cSamw 
423db3f65cSamw extern volatile uint32_t smb_fids;
433db3f65cSamw 
443db3f65cSamw static int smb_opipe_do_open(smb_request_t *, smb_opipe_t *);
45*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States static char *smb_opipe_lookup(const char *);
46*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States static int smb_opipe_sethdr(smb_opipe_t *, uint32_t, uint32_t);
47*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States static int smb_opipe_exec(smb_opipe_t *);
483db3f65cSamw static void smb_opipe_enter(smb_opipe_t *);
493db3f65cSamw static void smb_opipe_exit(smb_opipe_t *);
503db3f65cSamw 
513db3f65cSamw static door_handle_t smb_opipe_door_hd = NULL;
523db3f65cSamw static int smb_opipe_door_id = -1;
533db3f65cSamw static uint64_t smb_opipe_door_ncall = 0;
543db3f65cSamw static kmutex_t smb_opipe_door_mutex;
553db3f65cSamw static kcondvar_t smb_opipe_door_cv;
563db3f65cSamw 
573db3f65cSamw static int smb_opipe_door_call(smb_opipe_t *);
583db3f65cSamw static int smb_opipe_door_upcall(smb_opipe_t *);
593db3f65cSamw 
60*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_opipe_t *
61*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_opipe_alloc(smb_server_t *sv)
62*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States {
63*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_opipe_t	*opipe;
64*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
65*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	opipe = kmem_cache_alloc(sv->si_cache_opipe, KM_SLEEP);
66*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
67*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	bzero(opipe, sizeof (smb_opipe_t));
68*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	mutex_init(&opipe->p_mutex, NULL, MUTEX_DEFAULT, NULL);
69*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	cv_init(&opipe->p_cv, NULL, CV_DEFAULT, NULL);
70*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	opipe->p_magic = SMB_OPIPE_MAGIC;
71*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	opipe->p_server = sv;
72*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
73*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_llist_enter(&sv->sv_opipe_list, RW_WRITER);
74*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_llist_insert_tail(&sv->sv_opipe_list, opipe);
75*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_llist_exit(&sv->sv_opipe_list);
76*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
77*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	return (opipe);
78*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
79*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
80*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States void
81*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_opipe_dealloc(smb_opipe_t *opipe)
82*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States {
83*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_server_t *sv;
84*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
85*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	SMB_OPIPE_VALID(opipe);
86*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	sv = opipe->p_server;
87*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	SMB_SERVER_VALID(sv);
88*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
89*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_llist_enter(&sv->sv_opipe_list, RW_WRITER);
90*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_llist_remove(&sv->sv_opipe_list, opipe);
91*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_llist_exit(&sv->sv_opipe_list);
92*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
93*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	opipe->p_magic = (uint32_t)~SMB_OPIPE_MAGIC;
94*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_event_destroy(opipe->p_event);
95*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	cv_destroy(&opipe->p_cv);
96*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	mutex_destroy(&opipe->p_mutex);
97*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
98*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	kmem_cache_free(sv->si_cache_opipe, opipe);
99*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
100*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
1013db3f65cSamw /*
1023db3f65cSamw  * smb_opipe_open
1033db3f65cSamw  *
1043db3f65cSamw  * Open a well-known RPC named pipe. This routine should be called if
1053db3f65cSamw  * a file open is requested on a share of type STYPE_IPC.
1063db3f65cSamw  * If we recognize the pipe, we setup a new ofile.
1073db3f65cSamw  *
1083db3f65cSamw  * Returns 0 on success, Otherwise an NT status is returned to indicate
1093db3f65cSamw  * an error.
1103db3f65cSamw  */
1113db3f65cSamw int
1123db3f65cSamw smb_opipe_open(smb_request_t *sr)
1133db3f65cSamw {
1148b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	open_param_t *op = &sr->arg.open;
1153db3f65cSamw 	smb_ofile_t *of;
1163db3f65cSamw 	smb_opipe_t *opipe;
117*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_doorhdr_t hdr;
1183db3f65cSamw 	smb_error_t err;
1193db3f65cSamw 	char *pipe_name;
1203db3f65cSamw 
121eb1d736bSafshin salek ardakani - Sun Microsystems - Irvine United States 	if ((pipe_name = smb_opipe_lookup(op->fqi.fq_path.pn_path)) == NULL)
1223db3f65cSamw 		return (NT_STATUS_OBJECT_NAME_NOT_FOUND);
1233db3f65cSamw 
124c8ec8eeaSjose borrego 	op->create_options = 0;
125c8ec8eeaSjose borrego 
126c8ec8eeaSjose borrego 	of = smb_ofile_open(sr->tid_tree, NULL, sr->smb_pid, op,
1273db3f65cSamw 	    SMB_FTYPE_MESG_PIPE, SMB_UNIQ_FID(), &err);
1288b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
1293db3f65cSamw 	if (of == NULL)
1303db3f65cSamw 		return (err.status);
1313db3f65cSamw 
1328b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	if (!smb_tree_is_connected(sr->tid_tree)) {
1338b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		smb_ofile_close(of, 0);
1348b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		smb_ofile_release(of);
1358b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		return (NT_STATUS_OBJECT_NAME_NOT_FOUND);
1368b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	}
1378b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
1383db3f65cSamw 	op->dsize = 0x01000;
1393db3f65cSamw 	op->dattr = FILE_ATTRIBUTE_NORMAL;
1403db3f65cSamw 	op->ftype = SMB_FTYPE_MESG_PIPE;
1413db3f65cSamw 	op->action_taken = SMB_OACT_LOCK | SMB_OACT_OPENED; /* 0x8001 */
1423db3f65cSamw 	op->devstate = SMB_PIPE_READMODE_MESSAGE
1433db3f65cSamw 	    | SMB_PIPE_TYPE_MESSAGE
1443db3f65cSamw 	    | SMB_PIPE_UNLIMITED_INSTANCES; /* 0x05ff */
1453db3f65cSamw 	op->fileid = of->f_fid;
1463db3f65cSamw 
1473db3f65cSamw 	sr->smb_fid = of->f_fid;
1483db3f65cSamw 	sr->fid_ofile = of;
1493db3f65cSamw 
1503db3f65cSamw 	opipe = of->f_pipe;
1513db3f65cSamw 	smb_opipe_enter(opipe);
1523db3f65cSamw 
153*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	opipe->p_server = of->f_server;
1543db3f65cSamw 	opipe->p_name = pipe_name;
1553db3f65cSamw 	opipe->p_doorbuf = kmem_zalloc(SMB_OPIPE_DOOR_BUFSIZE, KM_SLEEP);
1563db3f65cSamw 
1573db3f65cSamw 	/*
1583db3f65cSamw 	 * p_data points to the offset within p_doorbuf at which
1593db3f65cSamw 	 * data will be written or read.
1603db3f65cSamw 	 */
161*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	opipe->p_data = opipe->p_doorbuf + xdr_sizeof(smb_doorhdr_xdr, &hdr);
1623db3f65cSamw 
1633db3f65cSamw 	if (smb_opipe_do_open(sr, opipe) != 0) {
1643db3f65cSamw 		/*
1653db3f65cSamw 		 * On error, reset the header to clear the fid,
1663db3f65cSamw 		 * which avoids confusion when smb_opipe_close() is
1673db3f65cSamw 		 * called by smb_ofile_close().
1683db3f65cSamw 		 */
169*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		bzero(&opipe->p_hdr, sizeof (smb_doorhdr_t));
1703db3f65cSamw 		kmem_free(opipe->p_doorbuf, SMB_OPIPE_DOOR_BUFSIZE);
1713db3f65cSamw 		smb_opipe_exit(opipe);
172c8ec8eeaSjose borrego 		smb_ofile_close(of, 0);
1733db3f65cSamw 		return (NT_STATUS_NO_MEMORY);
1743db3f65cSamw 	}
1753db3f65cSamw 	smb_opipe_exit(opipe);
1763db3f65cSamw 	return (NT_STATUS_SUCCESS);
1773db3f65cSamw }
1783db3f65cSamw 
1793db3f65cSamw /*
1803db3f65cSamw  * smb_opipe_lookup
1813db3f65cSamw  *
1823db3f65cSamw  * Lookup a path to see if it's a well-known RPC named pipe that we support.
1833db3f65cSamw  * The full pipe path will be in the form \\PIPE\\SERVICE.  The first part
1843db3f65cSamw  * can be assumed, so all we need here are the service names.
1853db3f65cSamw  *
1861fcced4cSJordan Brown  * Returns a pointer to the pipe name (without any leading \'s) on success.
1873db3f65cSamw  * Otherwise returns a null pointer.
1883db3f65cSamw  */
1893db3f65cSamw static char *
1903db3f65cSamw smb_opipe_lookup(const char *path)
1913db3f65cSamw {
1923db3f65cSamw 	static char *named_pipes[] = {
1931fcced4cSJordan Brown 		"lsass",
1943db3f65cSamw 		"LSARPC",
1953db3f65cSamw 		"NETLOGON",
1963db3f65cSamw 		"SAMR",
1973db3f65cSamw 		"SPOOLSS",
1983db3f65cSamw 		"SRVSVC",
1993db3f65cSamw 		"SVCCTL",
2003db3f65cSamw 		"WINREG",
2013db3f65cSamw 		"WKSSVC",
202*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		"EVENTLOG",
203*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		"NETDFS"
2043db3f65cSamw 	};
2053db3f65cSamw 
2063db3f65cSamw 	const char *name;
2073db3f65cSamw 	int i;
2083db3f65cSamw 
2093db3f65cSamw 	if (path == NULL)
2103db3f65cSamw 		return (NULL);
2113db3f65cSamw 
2123db3f65cSamw 	name = path;
2133db3f65cSamw 	name += strspn(name, "\\");
214bbf6f00cSJordan Brown 	if (smb_strcasecmp(name, "PIPE", 4) == 0) {
2153db3f65cSamw 		path += 4;
2163db3f65cSamw 		name += strspn(name, "\\");
2173db3f65cSamw 	}
2183db3f65cSamw 
2193db3f65cSamw 	for (i = 0; i < sizeof (named_pipes) / sizeof (named_pipes[0]); ++i) {
220bbf6f00cSJordan Brown 		if (smb_strcasecmp(name, named_pipes[i], 0) == 0)
2213db3f65cSamw 			return (named_pipes[i]);
2223db3f65cSamw 	}
2233db3f65cSamw 
2243db3f65cSamw 	return (NULL);
2253db3f65cSamw }
2263db3f65cSamw 
2273db3f65cSamw /*
2283db3f65cSamw  * Initialize the opipe header and context, and make the door call.
2293db3f65cSamw  */
2303db3f65cSamw static int
2313db3f65cSamw smb_opipe_do_open(smb_request_t *sr, smb_opipe_t *opipe)
2323db3f65cSamw {
2331fcced4cSJordan Brown 	smb_netuserinfo_t *userinfo = &opipe->p_user;
2343db3f65cSamw 	smb_user_t *user = sr->uid_user;
2353db3f65cSamw 	uint8_t *buf = opipe->p_doorbuf;
2363db3f65cSamw 	uint32_t buflen = SMB_OPIPE_DOOR_BUFSIZE;
2373db3f65cSamw 	uint32_t len;
2383db3f65cSamw 
239*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if ((opipe->p_event = smb_event_create()) == NULL)
240*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		return (-1);
241*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
2421fcced4cSJordan Brown 	smb_user_netinfo_init(user, userinfo);
2431fcced4cSJordan Brown 	len = xdr_sizeof(smb_netuserinfo_xdr, userinfo);
2443db3f65cSamw 
245*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	bzero(&opipe->p_hdr, sizeof (smb_doorhdr_t));
246*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	opipe->p_hdr.dh_magic = SMB_OPIPE_HDR_MAGIC;
247*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	opipe->p_hdr.dh_flags = SMB_DF_SYSSPACE;
248*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	opipe->p_hdr.dh_fid = smb_event_txid(opipe->p_event);
2493db3f65cSamw 
250*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if (smb_opipe_sethdr(opipe, SMB_OPIPE_OPEN, len) == -1)
2513db3f65cSamw 		return (-1);
2523db3f65cSamw 
253*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	len = xdr_sizeof(smb_doorhdr_xdr, &opipe->p_hdr);
2543db3f65cSamw 	buf += len;
2553db3f65cSamw 	buflen -= len;
2563db3f65cSamw 
2571fcced4cSJordan Brown 	if (smb_netuserinfo_encode(userinfo, buf, buflen, NULL) == -1)
2583db3f65cSamw 		return (-1);
2593db3f65cSamw 
2603db3f65cSamw 	return (smb_opipe_door_call(opipe));
2613db3f65cSamw }
2623db3f65cSamw 
2633db3f65cSamw /*
2643db3f65cSamw  * smb_opipe_close
2653db3f65cSamw  *
2663db3f65cSamw  * Called whenever an IPC file/pipe is closed.
2673db3f65cSamw  */
2683db3f65cSamw void
2693db3f65cSamw smb_opipe_close(smb_ofile_t *of)
2703db3f65cSamw {
2713db3f65cSamw 	smb_opipe_t *opipe;
2723db3f65cSamw 
2733db3f65cSamw 	ASSERT(of);
2743db3f65cSamw 	ASSERT(of->f_ftype == SMB_FTYPE_MESG_PIPE);
2753db3f65cSamw 
2763db3f65cSamw 	opipe = of->f_pipe;
277*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	SMB_OPIPE_VALID(opipe);
278*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
279*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	(void) smb_server_cancel_event(opipe->p_hdr.dh_fid);
2803db3f65cSamw 	smb_opipe_enter(opipe);
2813db3f65cSamw 
2823db3f65cSamw 	if (SMB_OPIPE_ISOPEN(opipe)) {
283*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		(void) smb_opipe_sethdr(opipe, SMB_OPIPE_CLOSE, 0);
2843db3f65cSamw 		(void) smb_opipe_door_call(opipe);
285*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		bzero(&opipe->p_hdr, sizeof (smb_doorhdr_t));
2863db3f65cSamw 		kmem_free(opipe->p_doorbuf, SMB_OPIPE_DOOR_BUFSIZE);
2873db3f65cSamw 	}
2883db3f65cSamw 
2891fcced4cSJordan Brown 	smb_user_netinfo_fini(&opipe->p_user);
2903db3f65cSamw 	smb_opipe_exit(opipe);
2913db3f65cSamw }
2923db3f65cSamw 
2933db3f65cSamw static int
294*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_opipe_sethdr(smb_opipe_t *opipe, uint32_t cmd, uint32_t datalen)
2953db3f65cSamw {
296*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	opipe->p_hdr.dh_op = cmd;
297*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	opipe->p_hdr.dh_txid = opipe->p_hdr.dh_fid;
298*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	opipe->p_hdr.dh_datalen = datalen;
299*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	opipe->p_hdr.dh_resid = 0;
300*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	opipe->p_hdr.dh_door_rc = EINVAL;
3013db3f65cSamw 
302*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	return (smb_doorhdr_encode(&opipe->p_hdr, opipe->p_doorbuf,
3033db3f65cSamw 	    SMB_OPIPE_DOOR_BUFSIZE));
3043db3f65cSamw }
3053db3f65cSamw 
3063db3f65cSamw /*
3073db3f65cSamw  * smb_opipe_transact
3083db3f65cSamw  *
3093db3f65cSamw  * This is the entry point for RPC bind and request transactions.
3103db3f65cSamw  * The fid is an arbitrary id used to associate RPC requests with a
3113db3f65cSamw  * particular binding handle.
3123db3f65cSamw  *
3133db3f65cSamw  * If the data to be returned is larger than the client expects, we
3143db3f65cSamw  * return as much as the client can handle and report a buffer overflow
3153db3f65cSamw  * warning, which informs the client that we have more data to return.
3163db3f65cSamw  * The residual data remains in the pipe until the client claims it or
3173db3f65cSamw  * closes the pipe.
3183db3f65cSamw  */
3193db3f65cSamw smb_sdrc_t
3203db3f65cSamw smb_opipe_transact(smb_request_t *sr, struct uio *uio)
3213db3f65cSamw {
3223db3f65cSamw 	smb_xa_t *xa;
3233db3f65cSamw 	smb_opipe_t *opipe;
3243db3f65cSamw 	struct mbuf *mhead;
3253db3f65cSamw 	int mdrcnt;
3263db3f65cSamw 	int nbytes;
3273db3f65cSamw 	int rc;
3283db3f65cSamw 
3293db3f65cSamw 	if ((rc = smb_opipe_write(sr, uio)) != 0) {
3303db3f65cSamw 		if (rc == EBADF)
3313db3f65cSamw 			smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
3323db3f65cSamw 			    ERRDOS, ERROR_INVALID_HANDLE);
3333db3f65cSamw 		else
3343db3f65cSamw 			smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
3353db3f65cSamw 			    ERRDOS, ERROR_INTERNAL_ERROR);
3363db3f65cSamw 		return (SDRC_ERROR);
3373db3f65cSamw 	}
3383db3f65cSamw 
339*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	opipe = sr->fid_ofile->f_pipe;
340*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
341*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if ((rc = smb_opipe_exec(opipe)) != 0) {
342*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
343*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		    ERRDOS, ERROR_INTERNAL_ERROR);
344*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		return (SDRC_ERROR);
345*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	}
346*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
3473db3f65cSamw 	xa = sr->r_xa;
3483db3f65cSamw 	mdrcnt = xa->smb_mdrcnt;
3493db3f65cSamw 	smb_opipe_enter(opipe);
3503db3f65cSamw 
351*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if (smb_opipe_sethdr(opipe, SMB_OPIPE_READ, mdrcnt) == -1) {
3523db3f65cSamw 		smb_opipe_exit(opipe);
3533db3f65cSamw 		smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
3543db3f65cSamw 		    ERRDOS, ERROR_INTERNAL_ERROR);
3553db3f65cSamw 		return (SDRC_ERROR);
3563db3f65cSamw 	}
3573db3f65cSamw 
3583db3f65cSamw 	rc = smb_opipe_door_call(opipe);
359*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	nbytes = opipe->p_hdr.dh_datalen;
3603db3f65cSamw 
3613db3f65cSamw 	if (rc != 0) {
3623db3f65cSamw 		smb_opipe_exit(opipe);
3633db3f65cSamw 		smbsr_error(sr, NT_STATUS_INTERNAL_ERROR,
3643db3f65cSamw 		    ERRDOS, ERROR_INTERNAL_ERROR);
3653db3f65cSamw 		return (SDRC_ERROR);
3663db3f65cSamw 	}
3673db3f65cSamw 
3683db3f65cSamw 	if (nbytes) {
3693db3f65cSamw 		mhead = smb_mbuf_get(opipe->p_data, nbytes);
3703db3f65cSamw 		xa->rep_data_mb.max_bytes = nbytes;
3713db3f65cSamw 		MBC_ATTACH_MBUF(&xa->rep_data_mb, mhead);
3723db3f65cSamw 	}
3733db3f65cSamw 
374*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if (opipe->p_hdr.dh_resid) {
3753db3f65cSamw 		/*
3763db3f65cSamw 		 * The pipe contains more data than mdrcnt, warn the
3773db3f65cSamw 		 * client that there is more data in the pipe.
3783db3f65cSamw 		 * Typically, the client will call SmbReadX, which
3793db3f65cSamw 		 * will call smb_opipe_read, to get the data.
3803db3f65cSamw 		 */
3813db3f65cSamw 		smbsr_warn(sr, NT_STATUS_BUFFER_OVERFLOW,
3823db3f65cSamw 		    ERRDOS, ERROR_MORE_DATA);
3833db3f65cSamw 	}
3843db3f65cSamw 
3853db3f65cSamw 	smb_opipe_exit(opipe);
3863db3f65cSamw 	return (SDRC_SUCCESS);
3873db3f65cSamw }
3883db3f65cSamw 
3893db3f65cSamw /*
3903db3f65cSamw  * smb_opipe_write
3913db3f65cSamw  *
3923db3f65cSamw  * Write RPC request data to the pipe.  The client should call smb_opipe_read
3933db3f65cSamw  * to complete the exchange and obtain the RPC response.
3943db3f65cSamw  *
3953db3f65cSamw  * Returns 0 on success or an errno on failure.
3963db3f65cSamw  */
3973db3f65cSamw int
3983db3f65cSamw smb_opipe_write(smb_request_t *sr, struct uio *uio)
3993db3f65cSamw {
4003db3f65cSamw 	smb_opipe_t *opipe;
4013db3f65cSamw 	uint32_t buflen;
4023db3f65cSamw 	uint32_t len;
4033db3f65cSamw 	int rc;
4043db3f65cSamw 
4053db3f65cSamw 	ASSERT(sr->fid_ofile);
4063db3f65cSamw 	ASSERT(sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE);
4073db3f65cSamw 
4083db3f65cSamw 	opipe = sr->fid_ofile->f_pipe;
409*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	SMB_OPIPE_VALID(opipe);
4103db3f65cSamw 	smb_opipe_enter(opipe);
4113db3f65cSamw 
4123db3f65cSamw 	if (!SMB_OPIPE_ISOPEN(opipe)) {
4133db3f65cSamw 		smb_opipe_exit(opipe);
4143db3f65cSamw 		return (EBADF);
4153db3f65cSamw 	}
4163db3f65cSamw 
417*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	rc = smb_opipe_sethdr(opipe, SMB_OPIPE_WRITE, uio->uio_resid);
418*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	len = xdr_sizeof(smb_doorhdr_xdr, &opipe->p_hdr);
4193db3f65cSamw 	if (rc == -1 || len == 0) {
4203db3f65cSamw 		smb_opipe_exit(opipe);
4213db3f65cSamw 		return (ENOMEM);
4223db3f65cSamw 	}
4233db3f65cSamw 
4243db3f65cSamw 	buflen = SMB_OPIPE_DOOR_BUFSIZE - len;
4253db3f65cSamw 	(void) uiomove((caddr_t)opipe->p_data, buflen, UIO_WRITE, uio);
4263db3f65cSamw 
4273db3f65cSamw 	rc = smb_opipe_door_call(opipe);
4283db3f65cSamw 
4293db3f65cSamw 	smb_opipe_exit(opipe);
4303db3f65cSamw 	return ((rc == 0) ? 0 : EIO);
4313db3f65cSamw }
4323db3f65cSamw 
4333db3f65cSamw /*
4343db3f65cSamw  * smb_opipe_read
4353db3f65cSamw  *
4363db3f65cSamw  * This interface may be called because smb_opipe_transact could not return
4373db3f65cSamw  * all of the data in the original transaction or to form the second half
4383db3f65cSamw  * of a transaction set up using smb_opipe_write.  Either way, we just need
4393db3f65cSamw  * to read data from the pipe and return it.
4403db3f65cSamw  *
4413db3f65cSamw  * The response data is encoded into raw_data as required by the smb_read
4423db3f65cSamw  * functions.  The uio_resid value indicates the number of bytes read.
4433db3f65cSamw  */
4443db3f65cSamw int
4453db3f65cSamw smb_opipe_read(smb_request_t *sr, struct uio *uio)
4463db3f65cSamw {
4473db3f65cSamw 	smb_opipe_t *opipe;
4483db3f65cSamw 	struct mbuf *mhead;
4493db3f65cSamw 	uint32_t nbytes;
4503db3f65cSamw 	int rc;
4513db3f65cSamw 
4523db3f65cSamw 	ASSERT(sr->fid_ofile);
4533db3f65cSamw 	ASSERT(sr->fid_ofile->f_ftype == SMB_FTYPE_MESG_PIPE);
4543db3f65cSamw 
4553db3f65cSamw 	opipe = sr->fid_ofile->f_pipe;
456*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	SMB_OPIPE_VALID(opipe);
457*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
458*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if ((rc = smb_opipe_exec(opipe)) != 0)
459*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		return (EIO);
460*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
4613db3f65cSamw 	smb_opipe_enter(opipe);
4623db3f65cSamw 
4633db3f65cSamw 	if (!SMB_OPIPE_ISOPEN(opipe)) {
4643db3f65cSamw 		smb_opipe_exit(opipe);
4653db3f65cSamw 		return (EBADF);
4663db3f65cSamw 	}
4673db3f65cSamw 
468*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if (smb_opipe_sethdr(opipe, SMB_OPIPE_READ, uio->uio_resid) == -1) {
4693db3f65cSamw 		smb_opipe_exit(opipe);
4703db3f65cSamw 		return (ENOMEM);
4713db3f65cSamw 	}
4723db3f65cSamw 
4733db3f65cSamw 	rc = smb_opipe_door_call(opipe);
474*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	nbytes = opipe->p_hdr.dh_datalen;
4753db3f65cSamw 
4763db3f65cSamw 	if (rc != 0 || nbytes > uio->uio_resid) {
4773db3f65cSamw 		smb_opipe_exit(opipe);
4783db3f65cSamw 		return (EIO);
4793db3f65cSamw 	}
4803db3f65cSamw 
4813db3f65cSamw 	if (nbytes) {
4823db3f65cSamw 		mhead = smb_mbuf_get(opipe->p_data, nbytes);
4833db3f65cSamw 		MBC_SETUP(&sr->raw_data, nbytes);
4843db3f65cSamw 		MBC_ATTACH_MBUF(&sr->raw_data, mhead);
4853db3f65cSamw 		uio->uio_resid -= nbytes;
4863db3f65cSamw 	}
4873db3f65cSamw 
4883db3f65cSamw 	smb_opipe_exit(opipe);
4893db3f65cSamw 	return (rc);
4903db3f65cSamw }
4913db3f65cSamw 
492*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States static int
493*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_opipe_exec(smb_opipe_t *opipe)
494*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States {
495*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	uint32_t	len;
496*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	int		rc;
497*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
498*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_opipe_enter(opipe);
499*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
500*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	rc = smb_opipe_sethdr(opipe, SMB_OPIPE_EXEC, 0);
501*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	len = xdr_sizeof(smb_doorhdr_xdr, &opipe->p_hdr);
502*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if (rc == -1 || len == 0) {
503*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		smb_opipe_exit(opipe);
504*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		return (ENOMEM);
505*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	}
506*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
507*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if ((rc = smb_opipe_door_call(opipe)) == 0)
508*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		rc = smb_event_wait(opipe->p_event);
509*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
510*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_opipe_exit(opipe);
511*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	return (rc);
512*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
513*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
5143db3f65cSamw /*
5153db3f65cSamw  * Named pipe I/O is serialized per fid to ensure that each request
5163db3f65cSamw  * has exclusive opipe access for the duration of the request.
5173db3f65cSamw  */
5183db3f65cSamw static void
5193db3f65cSamw smb_opipe_enter(smb_opipe_t *opipe)
5203db3f65cSamw {
5213db3f65cSamw 	mutex_enter(&opipe->p_mutex);
5223db3f65cSamw 
5233db3f65cSamw 	while (opipe->p_busy)
5243db3f65cSamw 		cv_wait(&opipe->p_cv, &opipe->p_mutex);
5253db3f65cSamw 
5263db3f65cSamw 	opipe->p_busy = 1;
5273db3f65cSamw 	mutex_exit(&opipe->p_mutex);
5283db3f65cSamw }
5293db3f65cSamw 
530*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States /*
531*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * Exit busy state.  If we have exec'd an RPC, we may have
532*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  * to wait for notification that processing has completed.
533*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States  */
5343db3f65cSamw static void
5353db3f65cSamw smb_opipe_exit(smb_opipe_t *opipe)
5363db3f65cSamw {
5373db3f65cSamw 	mutex_enter(&opipe->p_mutex);
5383db3f65cSamw 	opipe->p_busy = 0;
5393db3f65cSamw 	cv_signal(&opipe->p_cv);
5403db3f65cSamw 	mutex_exit(&opipe->p_mutex);
5413db3f65cSamw }
5423db3f65cSamw 
5433db3f65cSamw /*
5443db3f65cSamw  * opipe door client (to user space door server).
5453db3f65cSamw  */
5463db3f65cSamw void
5473db3f65cSamw smb_opipe_door_init(void)
5483db3f65cSamw {
5493db3f65cSamw 	mutex_init(&smb_opipe_door_mutex, NULL, MUTEX_DEFAULT, NULL);
5503db3f65cSamw 	cv_init(&smb_opipe_door_cv, NULL, CV_DEFAULT, NULL);
5513db3f65cSamw }
5523db3f65cSamw 
5533db3f65cSamw void
5543db3f65cSamw smb_opipe_door_fini(void)
5553db3f65cSamw {
5563db3f65cSamw 	smb_opipe_door_close();
5573db3f65cSamw 	cv_destroy(&smb_opipe_door_cv);
5583db3f65cSamw 	mutex_destroy(&smb_opipe_door_mutex);
5593db3f65cSamw }
5603db3f65cSamw 
5613db3f65cSamw /*
5623db3f65cSamw  * Open the (user space) door.  If the door is already open,
5633db3f65cSamw  * close it first because the door-id has probably changed.
5643db3f65cSamw  */
5653db3f65cSamw int
5663db3f65cSamw smb_opipe_door_open(int door_id)
5673db3f65cSamw {
5683db3f65cSamw 	smb_opipe_door_close();
5693db3f65cSamw 
5703db3f65cSamw 	mutex_enter(&smb_opipe_door_mutex);
5713db3f65cSamw 	smb_opipe_door_ncall = 0;
5723db3f65cSamw 
5733db3f65cSamw 	if (smb_opipe_door_hd == NULL) {
5743db3f65cSamw 		smb_opipe_door_id = door_id;
5753db3f65cSamw 		smb_opipe_door_hd = door_ki_lookup(door_id);
5763db3f65cSamw 	}
5773db3f65cSamw 
5783db3f65cSamw 	mutex_exit(&smb_opipe_door_mutex);
5793db3f65cSamw 	return ((smb_opipe_door_hd == NULL)  ? -1 : 0);
5803db3f65cSamw }
5813db3f65cSamw 
5823db3f65cSamw /*
5833db3f65cSamw  * Close the (user space) door.
5843db3f65cSamw  */
5853db3f65cSamw void
5863db3f65cSamw smb_opipe_door_close(void)
5873db3f65cSamw {
5883db3f65cSamw 	mutex_enter(&smb_opipe_door_mutex);
5893db3f65cSamw 
5903db3f65cSamw 	if (smb_opipe_door_hd != NULL) {
5913db3f65cSamw 		while (smb_opipe_door_ncall > 0)
5923db3f65cSamw 			cv_wait(&smb_opipe_door_cv, &smb_opipe_door_mutex);
5933db3f65cSamw 
5943db3f65cSamw 		door_ki_rele(smb_opipe_door_hd);
5953db3f65cSamw 		smb_opipe_door_hd = NULL;
5963db3f65cSamw 	}
5973db3f65cSamw 
5983db3f65cSamw 	mutex_exit(&smb_opipe_door_mutex);
5993db3f65cSamw }
6003db3f65cSamw 
6013db3f65cSamw /*
6023db3f65cSamw  * opipe door call interface.
6033db3f65cSamw  * Door serialization and call reference accounting is handled here.
6043db3f65cSamw  */
6053db3f65cSamw static int
6063db3f65cSamw smb_opipe_door_call(smb_opipe_t *opipe)
6073db3f65cSamw {
6083db3f65cSamw 	int rc;
6093db3f65cSamw 
6103db3f65cSamw 	mutex_enter(&smb_opipe_door_mutex);
6113db3f65cSamw 
6123db3f65cSamw 	if (smb_opipe_door_hd == NULL) {
6133db3f65cSamw 		mutex_exit(&smb_opipe_door_mutex);
6143db3f65cSamw 
6153db3f65cSamw 		if (smb_opipe_door_open(smb_opipe_door_id) != 0)
6163db3f65cSamw 			return (-1);
6173db3f65cSamw 
6183db3f65cSamw 		mutex_enter(&smb_opipe_door_mutex);
6193db3f65cSamw 	}
6203db3f65cSamw 
6213db3f65cSamw 	++smb_opipe_door_ncall;
6223db3f65cSamw 	mutex_exit(&smb_opipe_door_mutex);
6233db3f65cSamw 
6243db3f65cSamw 	rc = smb_opipe_door_upcall(opipe);
6253db3f65cSamw 
6263db3f65cSamw 	mutex_enter(&smb_opipe_door_mutex);
627*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if ((--smb_opipe_door_ncall) == 0)
6283db3f65cSamw 		cv_signal(&smb_opipe_door_cv);
6293db3f65cSamw 	mutex_exit(&smb_opipe_door_mutex);
6303db3f65cSamw 	return (rc);
6313db3f65cSamw }
6323db3f65cSamw 
6333db3f65cSamw /*
6343db3f65cSamw  * Door upcall wrapper - handles data marshalling.
6353db3f65cSamw  * This function should only be called by smb_opipe_door_call.
6363db3f65cSamw  */
6373db3f65cSamw static int
6383db3f65cSamw smb_opipe_door_upcall(smb_opipe_t *opipe)
6393db3f65cSamw {
6403db3f65cSamw 	door_arg_t da;
641*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_doorhdr_t hdr;
6423db3f65cSamw 	int i;
6433db3f65cSamw 	int rc;
6443db3f65cSamw 
6453db3f65cSamw 	da.data_ptr = (char *)opipe->p_doorbuf;
6463db3f65cSamw 	da.data_size = SMB_OPIPE_DOOR_BUFSIZE;
6473db3f65cSamw 	da.desc_ptr = NULL;
6483db3f65cSamw 	da.desc_num = 0;
6493db3f65cSamw 	da.rbuf = (char *)opipe->p_doorbuf;
6503db3f65cSamw 	da.rsize = SMB_OPIPE_DOOR_BUFSIZE;
6513db3f65cSamw 
6523db3f65cSamw 	for (i = 0; i < 3; ++i) {
653*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		if (smb_server_is_stopping())
654*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			return (-1);
655*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
6563db3f65cSamw 		if ((rc = door_ki_upcall_limited(smb_opipe_door_hd, &da,
6573db3f65cSamw 		    NULL, SIZE_MAX, 0)) == 0)
6583db3f65cSamw 			break;
6593db3f65cSamw 
6603db3f65cSamw 		if (rc != EAGAIN && rc != EINTR)
6613db3f65cSamw 			return (-1);
6623db3f65cSamw 	}
6633db3f65cSamw 
664*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	/* Check for door_return(NULL, 0, NULL, 0) */
665*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if (rc != 0 || da.data_size == 0 || da.rsize == 0)
6663db3f65cSamw 		return (-1);
6673db3f65cSamw 
668*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if (smb_doorhdr_decode(&hdr, (uint8_t *)da.data_ptr, da.rsize) == -1)
6693db3f65cSamw 		return (-1);
6703db3f65cSamw 
671*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	if ((hdr.dh_magic != SMB_OPIPE_HDR_MAGIC) ||
672*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	    (hdr.dh_fid != opipe->p_hdr.dh_fid) ||
673*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	    (hdr.dh_op != opipe->p_hdr.dh_op) ||
674*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	    (hdr.dh_door_rc != 0) ||
675*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	    (hdr.dh_datalen > SMB_OPIPE_DOOR_BUFSIZE)) {
6763db3f65cSamw 		return (-1);
6773db3f65cSamw 	}
6783db3f65cSamw 
679*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	opipe->p_hdr.dh_datalen = hdr.dh_datalen;
680*9fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	opipe->p_hdr.dh_resid = hdr.dh_resid;
6813db3f65cSamw 	return (0);
6823db3f65cSamw }
683