xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_opipe.c (revision c0e6223659596f35116cc0c40b2f9df32e3d8faf)
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 /*
22148c5f43SAlan Wright  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23*c0e62236SGordon Ross  * Copyright 2011-2021 Tintri by DDN, Inc. All rights reserved.
24268cac54SGordon Ross  * Copyright 2022 RackTop Systems, Inc.
253db3f65cSamw  */
263db3f65cSamw 
273db3f65cSamw /*
283db3f65cSamw  * This module provides the interface to NDR RPC.
293db3f65cSamw  */
303db3f65cSamw 
313db3f65cSamw #include <sys/stat.h>
323db3f65cSamw #include <sys/uio.h>
333db3f65cSamw #include <sys/ksynch.h>
3468b2bbf2SGordon Ross #include <sys/stropts.h>
3568b2bbf2SGordon Ross #include <sys/socket.h>
3668b2bbf2SGordon Ross #include <sys/filio.h>
37bbf6f00cSJordan Brown #include <smbsrv/smb_kproto.h>
383db3f65cSamw #include <smbsrv/smb_xdr.h>
39adee6784SGordon Ross #include <smb/winioctl.h>
40a90cf9f2SGordon Ross 
41268cac54SGordon Ross static uint32_t smb_opipe_wait(smb_request_t *, smb_fsctl_t *);
42268cac54SGordon Ross 
4368b2bbf2SGordon Ross /*
4468b2bbf2SGordon Ross  * Allocate a new opipe and return it, or NULL, in which case
4568b2bbf2SGordon Ross  * the caller will report "internal error".
4668b2bbf2SGordon Ross  */
4768b2bbf2SGordon Ross static smb_opipe_t *
4868b2bbf2SGordon Ross smb_opipe_alloc(smb_request_t *sr)
499fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States {
5068b2bbf2SGordon Ross 	smb_server_t	*sv = sr->sr_server;
519fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_opipe_t	*opipe;
5268b2bbf2SGordon Ross 	ksocket_t	sock;
5368b2bbf2SGordon Ross 
5468b2bbf2SGordon Ross 	if (ksocket_socket(&sock, AF_UNIX, SOCK_STREAM, 0,
5568b2bbf2SGordon Ross 	    KSOCKET_SLEEP, sr->user_cr) != 0)
5668b2bbf2SGordon Ross 		return (NULL);
579fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
588622ec45SGordon Ross 	opipe = kmem_cache_alloc(smb_cache_opipe, KM_SLEEP);
599fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
609fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	bzero(opipe, sizeof (smb_opipe_t));
619fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	mutex_init(&opipe->p_mutex, NULL, MUTEX_DEFAULT, NULL);
629fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	cv_init(&opipe->p_cv, NULL, CV_DEFAULT, NULL);
639fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	opipe->p_magic = SMB_OPIPE_MAGIC;
649fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	opipe->p_server = sv;
6568b2bbf2SGordon Ross 	opipe->p_refcnt = 1;
6668b2bbf2SGordon Ross 	opipe->p_socket = sock;
679fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
689fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	return (opipe);
699fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
709fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
7168b2bbf2SGordon Ross /*
7268b2bbf2SGordon Ross  * Destroy an opipe.  This is normally called from smb_ofile_delete
7368b2bbf2SGordon Ross  * when the ofile has no more references and is about to be free'd.
7468b2bbf2SGordon Ross  * This is also called here in error handling code paths, before
7568b2bbf2SGordon Ross  * the opipe is installed under an ofile.
7668b2bbf2SGordon Ross  */
779fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States void
789fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_opipe_dealloc(smb_opipe_t *opipe)
799fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States {
809fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_server_t *sv;
819fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
829fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	SMB_OPIPE_VALID(opipe);
839fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	sv = opipe->p_server;
849fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	SMB_SERVER_VALID(sv);
859fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
8668b2bbf2SGordon Ross 	/*
8768b2bbf2SGordon Ross 	 * This is called in the error path when opening,
8868b2bbf2SGordon Ross 	 * in which case we close the socket here.
8968b2bbf2SGordon Ross 	 */
9068b2bbf2SGordon Ross 	if (opipe->p_socket != NULL)
9168b2bbf2SGordon Ross 		(void) ksocket_close(opipe->p_socket, zone_kcred());
929fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
939fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	opipe->p_magic = (uint32_t)~SMB_OPIPE_MAGIC;
949fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	cv_destroy(&opipe->p_cv);
959fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	mutex_destroy(&opipe->p_mutex);
969fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
978622ec45SGordon Ross 	kmem_cache_free(smb_cache_opipe, opipe);
989fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
999fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
1003db3f65cSamw /*
101b210fedeSGordon Ross  * Unblock a request that might be blocked reading some
102b210fedeSGordon Ross  * pipe (AF_UNIX socket).  We don't have an easy way to
103b210fedeSGordon Ross  * interrupt just the thread servicing this request, so
104b210fedeSGordon Ross  * we shutdown(3socket) the socket, waking all readers.
105b210fedeSGordon Ross  * That's a bit heavy-handed, making the socket unusable
106b210fedeSGordon Ross  * after this, so we do this only when disconnecting a
107b210fedeSGordon Ross  * session (i.e. stopping the SMB service), and not when
108b210fedeSGordon Ross  * handling an SMB2_cancel or SMB_nt_cancel request.
109b210fedeSGordon Ross  */
110b210fedeSGordon Ross static void
111b210fedeSGordon Ross smb_opipe_cancel(smb_request_t *sr)
112b210fedeSGordon Ross {
113b210fedeSGordon Ross 	ksocket_t so;
114b210fedeSGordon Ross 
115811599a4SMatt Barden 	switch (sr->session->s_state) {
116811599a4SMatt Barden 	case SMB_SESSION_STATE_DISCONNECTED:
117811599a4SMatt Barden 	case SMB_SESSION_STATE_TERMINATED:
118811599a4SMatt Barden 		if ((so = sr->cancel_arg2) != NULL)
119b210fedeSGordon Ross 			(void) ksocket_shutdown(so, SHUT_RDWR, sr->user_cr);
120811599a4SMatt Barden 		break;
121b210fedeSGordon Ross 	}
122b210fedeSGordon Ross }
123b210fedeSGordon Ross 
124b210fedeSGordon Ross /*
12568b2bbf2SGordon Ross  * Helper for open: build pipe name and connect.
12668b2bbf2SGordon Ross  */
12768b2bbf2SGordon Ross static int
12868b2bbf2SGordon Ross smb_opipe_connect(smb_request_t *sr, smb_opipe_t *opipe)
12968b2bbf2SGordon Ross {
13068b2bbf2SGordon Ross 	struct sockaddr_un saddr;
13168b2bbf2SGordon Ross 	smb_arg_open_t	*op = &sr->sr_open;
13268b2bbf2SGordon Ross 	const char *name;
13368b2bbf2SGordon Ross 	int rc;
13468b2bbf2SGordon Ross 
13568b2bbf2SGordon Ross 	name = op->fqi.fq_path.pn_path;
13668b2bbf2SGordon Ross 	name += strspn(name, "\\");
13768b2bbf2SGordon Ross 	if (smb_strcasecmp(name, "PIPE", 4) == 0) {
13868b2bbf2SGordon Ross 		name += 4;
13968b2bbf2SGordon Ross 		name += strspn(name, "\\");
14068b2bbf2SGordon Ross 	}
14168b2bbf2SGordon Ross 	(void) strlcpy(opipe->p_name, name, SMB_OPIPE_MAXNAME);
14268b2bbf2SGordon Ross 	(void) smb_strlwr(opipe->p_name);
14368b2bbf2SGordon Ross 
14468b2bbf2SGordon Ross 	bzero(&saddr, sizeof (saddr));
14568b2bbf2SGordon Ross 	saddr.sun_family = AF_UNIX;
14668b2bbf2SGordon Ross 	(void) snprintf(saddr.sun_path, sizeof (saddr.sun_path),
14768b2bbf2SGordon Ross 	    "%s/%s", SMB_PIPE_DIR, opipe->p_name);
14868b2bbf2SGordon Ross 	rc = ksocket_connect(opipe->p_socket, (struct sockaddr *)&saddr,
14968b2bbf2SGordon Ross 	    sizeof (saddr), sr->user_cr);
15068b2bbf2SGordon Ross 
15168b2bbf2SGordon Ross 	return (rc);
15268b2bbf2SGordon Ross }
15368b2bbf2SGordon Ross 
154268cac54SGordon Ross static int
155268cac54SGordon Ross smb_opipe_exists(char *name)
156268cac54SGordon Ross {
157268cac54SGordon Ross 	struct sockaddr_un saddr;
158268cac54SGordon Ross 	vnode_t		*vp;	/* Underlying filesystem vnode */
159268cac54SGordon Ross 	int err;
160268cac54SGordon Ross 
161268cac54SGordon Ross 	bzero(&saddr, sizeof (saddr));
162268cac54SGordon Ross 	saddr.sun_family = AF_UNIX;
163268cac54SGordon Ross 	(void) snprintf(saddr.sun_path, sizeof (saddr.sun_path),
164268cac54SGordon Ross 	    "%s/%s", SMB_PIPE_DIR, name);
165268cac54SGordon Ross 
166268cac54SGordon Ross 	err = lookupname(saddr.sun_path, UIO_SYSSPACE, FOLLOW, NULLVPP, &vp);
167268cac54SGordon Ross 	if (err == 0) {
168268cac54SGordon Ross 		VN_RELE(vp);		/* release hold from lookup */
169268cac54SGordon Ross 	}
170268cac54SGordon Ross 
171268cac54SGordon Ross 	return (err);
172268cac54SGordon Ross }
173268cac54SGordon Ross 
174268cac54SGordon Ross 
17568b2bbf2SGordon Ross /*
17668b2bbf2SGordon Ross  * Helper for open: encode and send the user info.
17768b2bbf2SGordon Ross  *
17868b2bbf2SGordon Ross  * We send information about this client + user to the
17968b2bbf2SGordon Ross  * pipe service so it can use it for access checks.
18068b2bbf2SGordon Ross  * The service MAY deny the open based on this info,
18168b2bbf2SGordon Ross  * (i.e. anonymous session trying to open a pipe that
18268b2bbf2SGordon Ross  * requires authentication) in which case we will read
18368b2bbf2SGordon Ross  * an error status from the service and return that.
18468b2bbf2SGordon Ross  */
18568b2bbf2SGordon Ross static void
18668b2bbf2SGordon Ross smb_opipe_send_userinfo(smb_request_t *sr, smb_opipe_t *opipe,
18768b2bbf2SGordon Ross     smb_error_t *errp)
18868b2bbf2SGordon Ross {
18968b2bbf2SGordon Ross 	XDR xdrs;
19068b2bbf2SGordon Ross 	smb_netuserinfo_t nui;
19168b2bbf2SGordon Ross 	smb_pipehdr_t phdr;
19268b2bbf2SGordon Ross 	char *buf;
19368b2bbf2SGordon Ross 	uint32_t buflen;
19468b2bbf2SGordon Ross 	uint32_t status;
19568b2bbf2SGordon Ross 	size_t iocnt = 0;
19668b2bbf2SGordon Ross 	int rc;
19768b2bbf2SGordon Ross 
19868b2bbf2SGordon Ross 	/*
19968b2bbf2SGordon Ross 	 * Any errors building the XDR message etc.
20068b2bbf2SGordon Ross 	 */
20168b2bbf2SGordon Ross 	errp->status = NT_STATUS_INTERNAL_ERROR;
20268b2bbf2SGordon Ross 
20368b2bbf2SGordon Ross 	smb_user_netinfo_init(sr->uid_user, &nui);
20468b2bbf2SGordon Ross 	phdr.ph_magic = SMB_PIPE_HDR_MAGIC;
20568b2bbf2SGordon Ross 	phdr.ph_uilen = xdr_sizeof(smb_netuserinfo_xdr, &nui);
20668b2bbf2SGordon Ross 
20768b2bbf2SGordon Ross 	buflen = sizeof (phdr) + phdr.ph_uilen;
20868b2bbf2SGordon Ross 	buf = kmem_alloc(buflen, KM_SLEEP);
20968b2bbf2SGordon Ross 
21068b2bbf2SGordon Ross 	bcopy(&phdr, buf, sizeof (phdr));
21168b2bbf2SGordon Ross 	xdrmem_create(&xdrs, buf + sizeof (phdr),
21268b2bbf2SGordon Ross 	    buflen - (sizeof (phdr)), XDR_ENCODE);
21368b2bbf2SGordon Ross 	if (!smb_netuserinfo_xdr(&xdrs, &nui))
21468b2bbf2SGordon Ross 		goto out;
21568b2bbf2SGordon Ross 
216b210fedeSGordon Ross 	mutex_enter(&sr->sr_mutex);
217b210fedeSGordon Ross 	if (sr->sr_state != SMB_REQ_STATE_ACTIVE) {
218b210fedeSGordon Ross 		mutex_exit(&sr->sr_mutex);
219b210fedeSGordon Ross 		errp->status = NT_STATUS_CANCELLED;
220b210fedeSGordon Ross 		goto out;
221b210fedeSGordon Ross 	}
222b210fedeSGordon Ross 	sr->sr_state = SMB_REQ_STATE_WAITING_PIPE;
223b210fedeSGordon Ross 	sr->cancel_method = smb_opipe_cancel;
224b210fedeSGordon Ross 	sr->cancel_arg2 = opipe->p_socket;
225b210fedeSGordon Ross 	mutex_exit(&sr->sr_mutex);
22668b2bbf2SGordon Ross 
22768b2bbf2SGordon Ross 	rc = ksocket_send(opipe->p_socket, buf, buflen, 0,
22868b2bbf2SGordon Ross 	    &iocnt, sr->user_cr);
22968b2bbf2SGordon Ross 	if (rc == 0 && iocnt != buflen)
23068b2bbf2SGordon Ross 		rc = EIO;
231b210fedeSGordon Ross 	if (rc == 0)
232b210fedeSGordon Ross 		rc = ksocket_recv(opipe->p_socket, &status, sizeof (status),
233b210fedeSGordon Ross 		    0, &iocnt, sr->user_cr);
234b210fedeSGordon Ross 	if (rc == 0 && iocnt != sizeof (status))
235b210fedeSGordon Ross 		rc = EIO;
23668b2bbf2SGordon Ross 
237b210fedeSGordon Ross 	mutex_enter(&sr->sr_mutex);
238b210fedeSGordon Ross 	sr->cancel_method = NULL;
239b210fedeSGordon Ross 	sr->cancel_arg2 = NULL;
240b210fedeSGordon Ross 	switch (sr->sr_state) {
241b210fedeSGordon Ross 	case SMB_REQ_STATE_WAITING_PIPE:
242b210fedeSGordon Ross 		sr->sr_state = SMB_REQ_STATE_ACTIVE;
243b210fedeSGordon Ross 		break;
244b210fedeSGordon Ross 	case SMB_REQ_STATE_CANCEL_PENDING:
245b210fedeSGordon Ross 		sr->sr_state = SMB_REQ_STATE_CANCELLED;
246b210fedeSGordon Ross 		rc = EINTR;
247b210fedeSGordon Ross 		break;
248b210fedeSGordon Ross 	default:
249b210fedeSGordon Ross 		/* keep rc from above */
250b210fedeSGordon Ross 		break;
251b210fedeSGordon Ross 	}
252b210fedeSGordon Ross 	mutex_exit(&sr->sr_mutex);
253b210fedeSGordon Ross 
25468b2bbf2SGordon Ross 
25568b2bbf2SGordon Ross 	/*
25668b2bbf2SGordon Ross 	 * Return the status we read from the pipe service,
25768b2bbf2SGordon Ross 	 * normally NT_STATUS_SUCCESS, but could be something
25868b2bbf2SGordon Ross 	 * else like NT_STATUS_ACCESS_DENIED.
25968b2bbf2SGordon Ross 	 */
260b210fedeSGordon Ross 	switch (rc) {
261b210fedeSGordon Ross 	case 0:
26268b2bbf2SGordon Ross 		errp->status = status;
263b210fedeSGordon Ross 		break;
264b210fedeSGordon Ross 	case EINTR:
265b210fedeSGordon Ross 		errp->status = NT_STATUS_CANCELLED;
266b210fedeSGordon Ross 		break;
267b210fedeSGordon Ross 	/*
268b210fedeSGordon Ross 	 * If we fail sending the netuserinfo or recv'ing the
269b210fedeSGordon Ross 	 * status reponse, we have probably run into the limit
270b210fedeSGordon Ross 	 * on the number of open pipes.  That's this status:
271b210fedeSGordon Ross 	 */
272b210fedeSGordon Ross 	default:
273b210fedeSGordon Ross 		errp->status = NT_STATUS_PIPE_NOT_AVAILABLE;
274b210fedeSGordon Ross 		break;
275b210fedeSGordon Ross 	}
27668b2bbf2SGordon Ross 
27768b2bbf2SGordon Ross out:
27868b2bbf2SGordon Ross 	xdr_destroy(&xdrs);
27968b2bbf2SGordon Ross 	kmem_free(buf, buflen);
28068b2bbf2SGordon Ross 	smb_user_netinfo_fini(&nui);
28168b2bbf2SGordon Ross }
28268b2bbf2SGordon Ross 
28368b2bbf2SGordon Ross /*
2843db3f65cSamw  * smb_opipe_open
2853db3f65cSamw  *
28668b2bbf2SGordon Ross  * Open an RPC named pipe. This routine should be called if
2873db3f65cSamw  * a file open is requested on a share of type STYPE_IPC.
2883db3f65cSamw  * If we recognize the pipe, we setup a new ofile.
2893db3f65cSamw  *
29068b2bbf2SGordon Ross  * Returns 0 on success, Otherwise an NT status code.
2913db3f65cSamw  */
2923db3f65cSamw int
29394047d49SGordon Ross smb_opipe_open(smb_request_t *sr, smb_ofile_t *ofile)
2943db3f65cSamw {
295148c5f43SAlan Wright 	smb_arg_open_t	*op = &sr->sr_open;
296c5f48fa5SGordon Ross 	smb_attr_t *ap = &op->fqi.fq_fattr;
2973db3f65cSamw 	smb_opipe_t *opipe;
2983db3f65cSamw 	smb_error_t err;
2993db3f65cSamw 
30068b2bbf2SGordon Ross 	opipe = smb_opipe_alloc(sr);
30168b2bbf2SGordon Ross 	if (opipe == NULL)
30268b2bbf2SGordon Ross 		return (NT_STATUS_INTERNAL_ERROR);
3033db3f65cSamw 
30468b2bbf2SGordon Ross 	if (smb_opipe_connect(sr, opipe) != 0) {
30568b2bbf2SGordon Ross 		smb_opipe_dealloc(opipe);
3068b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		return (NT_STATUS_OBJECT_NAME_NOT_FOUND);
3078b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	}
3088b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
30968b2bbf2SGordon Ross 	smb_opipe_send_userinfo(sr, opipe, &err);
31068b2bbf2SGordon Ross 	if (err.status != 0) {
31168b2bbf2SGordon Ross 		smb_opipe_dealloc(opipe);
31268b2bbf2SGordon Ross 		return (err.status);
31368b2bbf2SGordon Ross 	}
31468b2bbf2SGordon Ross 
31568b2bbf2SGordon Ross 	/*
31694047d49SGordon Ross 	 * We might have blocked in smb_opipe_connect long enough so
31794047d49SGordon Ross 	 * a tree disconnect might have happened.  In that case, we
31894047d49SGordon Ross 	 * would be adding an ofile to a tree that's disconnecting,
31994047d49SGordon Ross 	 * which would interfere with tear-down.
32068b2bbf2SGordon Ross 	 */
32194047d49SGordon Ross 	if (!smb_tree_is_connected(sr->tid_tree)) {
32268b2bbf2SGordon Ross 		smb_opipe_dealloc(opipe);
32394047d49SGordon Ross 		return (NT_STATUS_NETWORK_NAME_DELETED);
32468b2bbf2SGordon Ross 	}
32568b2bbf2SGordon Ross 
32694047d49SGordon Ross 	/*
32794047d49SGordon Ross 	 * Note: The new opipe is given to smb_ofile_open
32894047d49SGordon Ross 	 * via op->pipe
32994047d49SGordon Ross 	 */
33094047d49SGordon Ross 	op->pipe = opipe;
33194047d49SGordon Ross 	smb_ofile_open(sr, op, ofile);
33294047d49SGordon Ross 	op->pipe = NULL;
33394047d49SGordon Ross 
33468b2bbf2SGordon Ross 	/* An "up" pointer, for debug. */
33568b2bbf2SGordon Ross 	opipe->p_ofile = ofile;
33668b2bbf2SGordon Ross 
337c5f48fa5SGordon Ross 	/*
338c5f48fa5SGordon Ross 	 * Caller expects attributes in op->fqi
339c5f48fa5SGordon Ross 	 */
340c5f48fa5SGordon Ross 	(void) smb_opipe_getattr(ofile, &op->fqi.fq_fattr);
341c5f48fa5SGordon Ross 
342c5f48fa5SGordon Ross 	op->dsize = 0;
343c5f48fa5SGordon Ross 	op->dattr = ap->sa_dosattr;
344c5f48fa5SGordon Ross 	op->fileid = ap->sa_vattr.va_nodeid;
3453db3f65cSamw 	op->ftype = SMB_FTYPE_MESG_PIPE;
346c5f48fa5SGordon Ross 	op->action_taken = SMB_OACT_OPLOCK | SMB_OACT_OPENED;
3473db3f65cSamw 	op->devstate = SMB_PIPE_READMODE_MESSAGE
3483db3f65cSamw 	    | SMB_PIPE_TYPE_MESSAGE
3493db3f65cSamw 	    | SMB_PIPE_UNLIMITED_INSTANCES; /* 0x05ff */
3503db3f65cSamw 
35168b2bbf2SGordon Ross 	sr->smb_fid = ofile->f_fid;
35268b2bbf2SGordon Ross 	sr->fid_ofile = ofile;
3533db3f65cSamw 
3543db3f65cSamw 	return (NT_STATUS_SUCCESS);
3553db3f65cSamw }
3563db3f65cSamw 
3573db3f65cSamw /*
3583db3f65cSamw  * smb_opipe_close
3593db3f65cSamw  *
36068b2bbf2SGordon Ross  * Called by smb_ofile_close for pipes.
36168b2bbf2SGordon Ross  *
36268b2bbf2SGordon Ross  * Note: ksocket_close may block while waiting for
36368b2bbf2SGordon Ross  * any I/O threads with a hold to get out.
3643db3f65cSamw  */
3653db3f65cSamw void
3663db3f65cSamw smb_opipe_close(smb_ofile_t *of)
3673db3f65cSamw {
3683db3f65cSamw 	smb_opipe_t *opipe;
36968b2bbf2SGordon Ross 	ksocket_t sock;
3703db3f65cSamw 
37168b2bbf2SGordon Ross 	ASSERT(of->f_state == SMB_OFILE_STATE_CLOSING);
3723db3f65cSamw 	ASSERT(of->f_ftype == SMB_FTYPE_MESG_PIPE);
3733db3f65cSamw 	opipe = of->f_pipe;
3749fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	SMB_OPIPE_VALID(opipe);
3759fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
37668b2bbf2SGordon Ross 	mutex_enter(&opipe->p_mutex);
37768b2bbf2SGordon Ross 	sock = opipe->p_socket;
37868b2bbf2SGordon Ross 	opipe->p_socket = NULL;
37968b2bbf2SGordon Ross 	mutex_exit(&opipe->p_mutex);
3803db3f65cSamw 
38168b2bbf2SGordon Ross 	(void) ksocket_shutdown(sock, SHUT_RDWR, of->f_cr);
38268b2bbf2SGordon Ross 	(void) ksocket_close(sock, of->f_cr);
3833db3f65cSamw }
3843db3f65cSamw 
3853db3f65cSamw /*
3863db3f65cSamw  * smb_opipe_write
3873db3f65cSamw  *
3883db3f65cSamw  * Write RPC request data to the pipe.  The client should call smb_opipe_read
3893db3f65cSamw  * to complete the exchange and obtain the RPC response.
3903db3f65cSamw  *
3913db3f65cSamw  * Returns 0 on success or an errno on failure.
3923db3f65cSamw  */
3933db3f65cSamw int
3943db3f65cSamw smb_opipe_write(smb_request_t *sr, struct uio *uio)
3953db3f65cSamw {
39668b2bbf2SGordon Ross 	struct nmsghdr msghdr;
39768b2bbf2SGordon Ross 	smb_ofile_t *ofile;
3983db3f65cSamw 	smb_opipe_t *opipe;
39968b2bbf2SGordon Ross 	ksocket_t sock;
40068b2bbf2SGordon Ross 	size_t sent = 0;
40168b2bbf2SGordon Ross 	int rc = 0;
4023db3f65cSamw 
40368b2bbf2SGordon Ross 	ofile = sr->fid_ofile;
40468b2bbf2SGordon Ross 	ASSERT(ofile->f_ftype == SMB_FTYPE_MESG_PIPE);
40568b2bbf2SGordon Ross 	opipe = ofile->f_pipe;
4069fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	SMB_OPIPE_VALID(opipe);
4073db3f65cSamw 
40868b2bbf2SGordon Ross 	mutex_enter(&opipe->p_mutex);
40968b2bbf2SGordon Ross 	sock = opipe->p_socket;
41068b2bbf2SGordon Ross 	if (sock != NULL)
41168b2bbf2SGordon Ross 		ksocket_hold(sock);
41268b2bbf2SGordon Ross 	mutex_exit(&opipe->p_mutex);
41368b2bbf2SGordon Ross 	if (sock == NULL)
4143db3f65cSamw 		return (EBADF);
41568b2bbf2SGordon Ross 
41668b2bbf2SGordon Ross 	bzero(&msghdr, sizeof (msghdr));
41768b2bbf2SGordon Ross 	msghdr.msg_iov = uio->uio_iov;
41868b2bbf2SGordon Ross 	msghdr.msg_iovlen = uio->uio_iovcnt;
41968b2bbf2SGordon Ross 
42068b2bbf2SGordon Ross 	/*
42168b2bbf2SGordon Ross 	 * This should block until we've sent it all,
42268b2bbf2SGordon Ross 	 * or given up due to errors (pipe closed).
42368b2bbf2SGordon Ross 	 */
42468b2bbf2SGordon Ross 	while (uio->uio_resid > 0) {
42568b2bbf2SGordon Ross 		rc = ksocket_sendmsg(sock, &msghdr, 0, &sent, ofile->f_cr);
42668b2bbf2SGordon Ross 		if (rc != 0)
42768b2bbf2SGordon Ross 			break;
42868b2bbf2SGordon Ross 		uio->uio_resid -= sent;
4293db3f65cSamw 	}
4303db3f65cSamw 
43168b2bbf2SGordon Ross 	ksocket_rele(sock);
4323db3f65cSamw 
43368b2bbf2SGordon Ross 	return (rc);
4343db3f65cSamw }
4353db3f65cSamw 
4363db3f65cSamw /*
4373db3f65cSamw  * smb_opipe_read
4383db3f65cSamw  *
43968b2bbf2SGordon Ross  * This interface may be called from smb_opipe_transact (write, read)
44068b2bbf2SGordon Ross  * or from smb_read / smb2_read to get the rest of an RPC response.
44168b2bbf2SGordon Ross  * The response data (and length) are returned via the uio.
4423db3f65cSamw  */
4433db3f65cSamw int
4443db3f65cSamw smb_opipe_read(smb_request_t *sr, struct uio *uio)
4453db3f65cSamw {
44668b2bbf2SGordon Ross 	struct nmsghdr msghdr;
44768b2bbf2SGordon Ross 	smb_ofile_t *ofile;
4483db3f65cSamw 	smb_opipe_t *opipe;
44968b2bbf2SGordon Ross 	ksocket_t sock;
45068b2bbf2SGordon Ross 	size_t recvcnt = 0;
4513db3f65cSamw 	int rc;
4523db3f65cSamw 
45368b2bbf2SGordon Ross 	ofile = sr->fid_ofile;
45468b2bbf2SGordon Ross 	ASSERT(ofile->f_ftype == SMB_FTYPE_MESG_PIPE);
45568b2bbf2SGordon Ross 	opipe = ofile->f_pipe;
4569fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	SMB_OPIPE_VALID(opipe);
4579fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
45868b2bbf2SGordon Ross 	mutex_enter(&opipe->p_mutex);
45968b2bbf2SGordon Ross 	sock = opipe->p_socket;
46068b2bbf2SGordon Ross 	if (sock != NULL)
46168b2bbf2SGordon Ross 		ksocket_hold(sock);
46268b2bbf2SGordon Ross 	mutex_exit(&opipe->p_mutex);
46368b2bbf2SGordon Ross 	if (sock == NULL)
4643db3f65cSamw 		return (EBADF);
4653db3f65cSamw 
466b210fedeSGordon Ross 	mutex_enter(&sr->sr_mutex);
467b210fedeSGordon Ross 	if (sr->sr_state != SMB_REQ_STATE_ACTIVE) {
468b210fedeSGordon Ross 		mutex_exit(&sr->sr_mutex);
469b210fedeSGordon Ross 		rc = EINTR;
470b210fedeSGordon Ross 		goto out;
471b210fedeSGordon Ross 	}
472b210fedeSGordon Ross 	sr->sr_state = SMB_REQ_STATE_WAITING_PIPE;
473b210fedeSGordon Ross 	sr->cancel_method = smb_opipe_cancel;
474b210fedeSGordon Ross 	sr->cancel_arg2 = sock;
475b210fedeSGordon Ross 	mutex_exit(&sr->sr_mutex);
4769fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
4773db3f65cSamw 	/*
47868b2bbf2SGordon Ross 	 * This should block only if there's no data.
47968b2bbf2SGordon Ross 	 * A single call to recvmsg does just that.
48068b2bbf2SGordon Ross 	 * (Intentionaly no recv loop here.)
4813db3f65cSamw 	 */
482b210fedeSGordon Ross 	bzero(&msghdr, sizeof (msghdr));
483b210fedeSGordon Ross 	msghdr.msg_iov = uio->uio_iov;
484b210fedeSGordon Ross 	msghdr.msg_iovlen = uio->uio_iovcnt;
48568b2bbf2SGordon Ross 	rc = ksocket_recvmsg(sock, &msghdr, 0,
48668b2bbf2SGordon Ross 	    &recvcnt, ofile->f_cr);
487b210fedeSGordon Ross 
488b210fedeSGordon Ross 	mutex_enter(&sr->sr_mutex);
489b210fedeSGordon Ross 	sr->cancel_method = NULL;
490b210fedeSGordon Ross 	sr->cancel_arg2 = NULL;
491b210fedeSGordon Ross 	switch (sr->sr_state) {
492b210fedeSGordon Ross 	case SMB_REQ_STATE_WAITING_PIPE:
493b210fedeSGordon Ross 		sr->sr_state = SMB_REQ_STATE_ACTIVE;
494b210fedeSGordon Ross 		break;
495b210fedeSGordon Ross 	case SMB_REQ_STATE_CANCEL_PENDING:
496b210fedeSGordon Ross 		sr->sr_state = SMB_REQ_STATE_CANCELLED;
497b210fedeSGordon Ross 		rc = EINTR;
498b210fedeSGordon Ross 		break;
499b210fedeSGordon Ross 	default:
500b210fedeSGordon Ross 		/* keep rc from above */
501b210fedeSGordon Ross 		break;
502b210fedeSGordon Ross 	}
503b210fedeSGordon Ross 	mutex_exit(&sr->sr_mutex);
504b210fedeSGordon Ross 
50568b2bbf2SGordon Ross 	if (rc != 0)
50668b2bbf2SGordon Ross 		goto out;
5073db3f65cSamw 
50868b2bbf2SGordon Ross 	if (recvcnt == 0) {
50968b2bbf2SGordon Ross 		/* Other side closed. */
51068b2bbf2SGordon Ross 		rc = EPIPE;
51168b2bbf2SGordon Ross 		goto out;
5123db3f65cSamw 	}
51368b2bbf2SGordon Ross 	uio->uio_resid -= recvcnt;
5143db3f65cSamw 
515bce01b59SGordon Ross out:
516bce01b59SGordon Ross 	ksocket_rele(sock);
517bce01b59SGordon Ross 
518bce01b59SGordon Ross 	return (rc);
51968b2bbf2SGordon Ross }
52068b2bbf2SGordon Ross 
521bce01b59SGordon Ross int
522a90cf9f2SGordon Ross smb_opipe_ioctl(smb_request_t *sr, int cmd, void *arg, int *rvalp)
523bce01b59SGordon Ross {
524bce01b59SGordon Ross 	smb_ofile_t *ofile;
525bce01b59SGordon Ross 	smb_opipe_t *opipe;
526bce01b59SGordon Ross 	ksocket_t sock;
527a90cf9f2SGordon Ross 	int rc;
528bce01b59SGordon Ross 
529bce01b59SGordon Ross 	ofile = sr->fid_ofile;
530bce01b59SGordon Ross 	ASSERT(ofile->f_ftype == SMB_FTYPE_MESG_PIPE);
531bce01b59SGordon Ross 	opipe = ofile->f_pipe;
532bce01b59SGordon Ross 	SMB_OPIPE_VALID(opipe);
533bce01b59SGordon Ross 
534bce01b59SGordon Ross 	mutex_enter(&opipe->p_mutex);
535bce01b59SGordon Ross 	sock = opipe->p_socket;
536bce01b59SGordon Ross 	if (sock != NULL)
537bce01b59SGordon Ross 		ksocket_hold(sock);
538bce01b59SGordon Ross 	mutex_exit(&opipe->p_mutex);
539bce01b59SGordon Ross 	if (sock == NULL)
540bce01b59SGordon Ross 		return (EBADF);
541bce01b59SGordon Ross 
542a90cf9f2SGordon Ross 	rc = ksocket_ioctl(sock, cmd, (intptr_t)arg, rvalp, ofile->f_cr);
543bce01b59SGordon Ross 
54468b2bbf2SGordon Ross 	ksocket_rele(sock);
54568b2bbf2SGordon Ross 
54668b2bbf2SGordon Ross 	return (rc);
5473db3f65cSamw }
548a90cf9f2SGordon Ross 
549a90cf9f2SGordon Ross /*
550a90cf9f2SGordon Ross  * Get the smb_attr_t for a named pipe.
551a90cf9f2SGordon Ross  * Caller has already cleared to zero.
552a90cf9f2SGordon Ross  */
553a90cf9f2SGordon Ross int
554a90cf9f2SGordon Ross smb_opipe_getattr(smb_ofile_t *of, smb_attr_t *ap)
555a90cf9f2SGordon Ross {
556a90cf9f2SGordon Ross 
557a90cf9f2SGordon Ross 	if (of->f_pipe == NULL)
558a90cf9f2SGordon Ross 		return (EINVAL);
559a90cf9f2SGordon Ross 
560a90cf9f2SGordon Ross 	ap->sa_vattr.va_type = VFIFO;
561a90cf9f2SGordon Ross 	ap->sa_vattr.va_nlink = 1;
562c5f48fa5SGordon Ross 	ap->sa_vattr.va_nodeid = (uintptr_t)of->f_pipe;
563a90cf9f2SGordon Ross 	ap->sa_dosattr = FILE_ATTRIBUTE_NORMAL;
564c5f48fa5SGordon Ross 	ap->sa_allocsz = SMB_PIPE_MAX_MSGSIZE;
565a90cf9f2SGordon Ross 
566a90cf9f2SGordon Ross 	return (0);
567a90cf9f2SGordon Ross }
568a90cf9f2SGordon Ross 
569a90cf9f2SGordon Ross int
570a90cf9f2SGordon Ross smb_opipe_getname(smb_ofile_t *of, char *buf, size_t buflen)
571a90cf9f2SGordon Ross {
572a90cf9f2SGordon Ross 	smb_opipe_t *opipe;
573a90cf9f2SGordon Ross 
574a90cf9f2SGordon Ross 	if ((opipe = of->f_pipe) == NULL)
575a90cf9f2SGordon Ross 		return (EINVAL);
576a90cf9f2SGordon Ross 
577a90cf9f2SGordon Ross 	(void) snprintf(buf, buflen, "\\%s", opipe->p_name);
578a90cf9f2SGordon Ross 	return (0);
579a90cf9f2SGordon Ross }
580a90cf9f2SGordon Ross 
581a90cf9f2SGordon Ross /*
58255f0a249SGordon Ross  * Handle device type FILE_DEVICE_NAMED_PIPE
58355f0a249SGordon Ross  * for smb2_ioctl
584a90cf9f2SGordon Ross  */
585a90cf9f2SGordon Ross /* ARGSUSED */
586a90cf9f2SGordon Ross uint32_t
587a90cf9f2SGordon Ross smb_opipe_fsctl(smb_request_t *sr, smb_fsctl_t *fsctl)
588a90cf9f2SGordon Ross {
589a90cf9f2SGordon Ross 	uint32_t status;
590a90cf9f2SGordon Ross 
59155f0a249SGordon Ross 	if (!STYPE_ISIPC(sr->tid_tree->t_res_type))
59255f0a249SGordon Ross 		return (NT_STATUS_INVALID_DEVICE_REQUEST);
59355f0a249SGordon Ross 
594a90cf9f2SGordon Ross 	switch (fsctl->CtlCode) {
595a90cf9f2SGordon Ross 	case FSCTL_PIPE_TRANSCEIVE:
596a90cf9f2SGordon Ross 		status = smb_opipe_transceive(sr, fsctl);
597a90cf9f2SGordon Ross 		break;
598a90cf9f2SGordon Ross 
599a90cf9f2SGordon Ross 	case FSCTL_PIPE_PEEK:
600268cac54SGordon Ross 		status = NT_STATUS_INVALID_DEVICE_REQUEST;
601268cac54SGordon Ross 		break;
602268cac54SGordon Ross 
603a90cf9f2SGordon Ross 	case FSCTL_PIPE_WAIT:
604268cac54SGordon Ross 		status = smb_opipe_wait(sr, fsctl);
605a90cf9f2SGordon Ross 		break;
606a90cf9f2SGordon Ross 
607a90cf9f2SGordon Ross 	default:
608a90cf9f2SGordon Ross 		ASSERT(!"CtlCode");
609a90cf9f2SGordon Ross 		status = NT_STATUS_INTERNAL_ERROR;
610a90cf9f2SGordon Ross 		break;
611a90cf9f2SGordon Ross 	}
612a90cf9f2SGordon Ross 
613a90cf9f2SGordon Ross 	return (status);
614a90cf9f2SGordon Ross }
615a90cf9f2SGordon Ross 
61655f0a249SGordon Ross uint32_t
617a90cf9f2SGordon Ross smb_opipe_transceive(smb_request_t *sr, smb_fsctl_t *fsctl)
618a90cf9f2SGordon Ross {
619*c0e62236SGordon Ross 	smb_vdb_t	*vdb;
620a90cf9f2SGordon Ross 	smb_ofile_t	*ofile;
621a90cf9f2SGordon Ross 	struct mbuf	*mb;
622a90cf9f2SGordon Ross 	uint32_t	status;
623a90cf9f2SGordon Ross 	int		len, rc;
624a90cf9f2SGordon Ross 
625a90cf9f2SGordon Ross 	/*
626a90cf9f2SGordon Ross 	 * Caller checked that this is the IPC$ share,
627a90cf9f2SGordon Ross 	 * and that this call has a valid open handle.
628a90cf9f2SGordon Ross 	 * Just check the type.
629a90cf9f2SGordon Ross 	 */
630a90cf9f2SGordon Ross 	ofile = sr->fid_ofile;
631a90cf9f2SGordon Ross 	if (ofile->f_ftype != SMB_FTYPE_MESG_PIPE)
632a90cf9f2SGordon Ross 		return (NT_STATUS_INVALID_HANDLE);
633a90cf9f2SGordon Ross 
634*c0e62236SGordon Ross 	/*
635*c0e62236SGordon Ross 	 * The VDB is a bit large.  Allocate.
636*c0e62236SGordon Ross 	 * This is automatically free'd with the SR
637*c0e62236SGordon Ross 	 */
638*c0e62236SGordon Ross 	vdb = smb_srm_zalloc(sr, sizeof (*vdb));
639a90cf9f2SGordon Ross 	rc = smb_mbc_decodef(fsctl->in_mbc, "#B",
640*c0e62236SGordon Ross 	    fsctl->InputCount, vdb);
641a90cf9f2SGordon Ross 	if (rc != 0) {
642a90cf9f2SGordon Ross 		/* Not enough data sent. */
643a90cf9f2SGordon Ross 		return (NT_STATUS_INVALID_PARAMETER);
644a90cf9f2SGordon Ross 	}
645a90cf9f2SGordon Ross 
646*c0e62236SGordon Ross 	rc = smb_opipe_write(sr, &vdb->vdb_uio);
647a90cf9f2SGordon Ross 	if (rc != 0)
648a90cf9f2SGordon Ross 		return (smb_errno2status(rc));
649a90cf9f2SGordon Ross 
650*c0e62236SGordon Ross 	vdb->vdb_tag = 0;
651*c0e62236SGordon Ross 	vdb->vdb_uio.uio_iov = &vdb->vdb_iovec[0];
652*c0e62236SGordon Ross 	vdb->vdb_uio.uio_iovcnt = MAX_IOVEC;
653*c0e62236SGordon Ross 	vdb->vdb_uio.uio_segflg = UIO_SYSSPACE;
654*c0e62236SGordon Ross 	vdb->vdb_uio.uio_extflg = UIO_COPY_DEFAULT;
655*c0e62236SGordon Ross 	vdb->vdb_uio.uio_loffset = (offset_t)0;
656*c0e62236SGordon Ross 	vdb->vdb_uio.uio_resid = fsctl->MaxOutputResp;
657*c0e62236SGordon Ross 	mb = smb_mbuf_allocate(&vdb->vdb_uio);
658a90cf9f2SGordon Ross 
659*c0e62236SGordon Ross 	rc = smb_opipe_read(sr, &vdb->vdb_uio);
660a90cf9f2SGordon Ross 	if (rc != 0) {
661a90cf9f2SGordon Ross 		m_freem(mb);
662a90cf9f2SGordon Ross 		return (smb_errno2status(rc));
663a90cf9f2SGordon Ross 	}
664a90cf9f2SGordon Ross 
665*c0e62236SGordon Ross 	len = fsctl->MaxOutputResp - vdb->vdb_uio.uio_resid;
666a90cf9f2SGordon Ross 	smb_mbuf_trim(mb, len);
667a90cf9f2SGordon Ross 	MBC_ATTACH_MBUF(fsctl->out_mbc, mb);
668a90cf9f2SGordon Ross 
669a90cf9f2SGordon Ross 	/*
670a90cf9f2SGordon Ross 	 * If the output buffer holds a partial pipe message,
671a90cf9f2SGordon Ross 	 * we're supposed to return NT_STATUS_BUFFER_OVERFLOW.
672a90cf9f2SGordon Ross 	 * As we don't have message boundary markers, the best
673a90cf9f2SGordon Ross 	 * we can do is return that status when we have ALL of:
674a90cf9f2SGordon Ross 	 *	Output buffer was < SMB_PIPE_MAX_MSGSIZE
675a90cf9f2SGordon Ross 	 *	We filled the output buffer (resid==0)
676a90cf9f2SGordon Ross 	 *	There's more data (ioctl FIONREAD)
677a90cf9f2SGordon Ross 	 */
678a90cf9f2SGordon Ross 	status = NT_STATUS_SUCCESS;
679a90cf9f2SGordon Ross 	if (fsctl->MaxOutputResp < SMB_PIPE_MAX_MSGSIZE &&
680*c0e62236SGordon Ross 	    vdb->vdb_uio.uio_resid == 0) {
681a90cf9f2SGordon Ross 		int nread = 0, trval;
682a90cf9f2SGordon Ross 		rc = smb_opipe_ioctl(sr, FIONREAD, &nread, &trval);
683a90cf9f2SGordon Ross 		if (rc == 0 && nread != 0)
684a90cf9f2SGordon Ross 			status = NT_STATUS_BUFFER_OVERFLOW;
685a90cf9f2SGordon Ross 	}
686a90cf9f2SGordon Ross 
687a90cf9f2SGordon Ross 	return (status);
688a90cf9f2SGordon Ross }
689268cac54SGordon Ross 
690268cac54SGordon Ross static uint32_t
691268cac54SGordon Ross smb_opipe_wait(smb_request_t *sr, smb_fsctl_t *fsctl)
692268cac54SGordon Ross {
693268cac54SGordon Ross 	char		*name;
694268cac54SGordon Ross 	uint64_t	timeout;
695268cac54SGordon Ross 	uint32_t	namelen;
696268cac54SGordon Ross 	int		rc;
697268cac54SGordon Ross 	uint8_t		tflag;
698268cac54SGordon Ross 
699268cac54SGordon Ross 	rc = smb_mbc_decodef(fsctl->in_mbc, "qlb.",
700268cac54SGordon Ross 	    &timeout,	/* q */
701268cac54SGordon Ross 	    &namelen,	/* l */
702268cac54SGordon Ross 	    &tflag);	/* b */
703268cac54SGordon Ross 	if (rc != 0)
704268cac54SGordon Ross 		return (NT_STATUS_INVALID_PARAMETER);
705268cac54SGordon Ross 	rc = smb_mbc_decodef(fsctl->in_mbc, "%#U",
706268cac54SGordon Ross 	    sr,		/* % */
707268cac54SGordon Ross 	    namelen,	/* # */
708268cac54SGordon Ross 	    &name);	/* U */
709268cac54SGordon Ross 	if (rc != 0)
710268cac54SGordon Ross 		return (NT_STATUS_INVALID_PARAMETER);
711268cac54SGordon Ross 
712268cac54SGordon Ross 	rc = smb_opipe_exists(name);
713268cac54SGordon Ross 	if (rc != 0)
714268cac54SGordon Ross 		return (NT_STATUS_OBJECT_NAME_NOT_FOUND);
715268cac54SGordon Ross 
716268cac54SGordon Ross 	/*
717268cac54SGordon Ross 	 * At this point we know the pipe exists.
718268cac54SGordon Ross 	 *
719268cac54SGordon Ross 	 * If the tflag is set, we're supposed to wait for up to
720268cac54SGordon Ross 	 * timeout (100s of milliseconds) for a pipe "instance"
721268cac54SGordon Ross 	 * to become "available" (so pipe open would work).
722268cac54SGordon Ross 	 * However, this implementation has no need to wait,
723268cac54SGordon Ross 	 * so just take a short delay instead.
724268cac54SGordon Ross 	 */
725268cac54SGordon Ross 	if (tflag != 0) {
726268cac54SGordon Ross 		clock_t ticks = MSEC_TO_TICK(timeout * 100);
727268cac54SGordon Ross 		if (ticks > MSEC_TO_TICK(100))
728268cac54SGordon Ross 			ticks = MSEC_TO_TICK(100);
729268cac54SGordon Ross 		delay(ticks);
730268cac54SGordon Ross 	}
731268cac54SGordon Ross 
732268cac54SGordon Ross 	return (0);
733268cac54SGordon Ross }
734