xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_opipe.c (revision 68b2bbf26c7040fea4281dcb58b81e7627e46f34)
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*68b2bbf2SGordon Ross  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
243db3f65cSamw  */
253db3f65cSamw 
263db3f65cSamw /*
273db3f65cSamw  * This module provides the interface to NDR RPC.
283db3f65cSamw  */
293db3f65cSamw 
303db3f65cSamw #include <sys/stat.h>
313db3f65cSamw #include <sys/uio.h>
323db3f65cSamw #include <sys/ksynch.h>
33*68b2bbf2SGordon Ross #include <sys/stropts.h>
34*68b2bbf2SGordon Ross #include <sys/socket.h>
35*68b2bbf2SGordon Ross #include <sys/filio.h>
36bbf6f00cSJordan Brown #include <smbsrv/smb_kproto.h>
373db3f65cSamw #include <smbsrv/smb_xdr.h>
383db3f65cSamw 
39*68b2bbf2SGordon Ross /*
40*68b2bbf2SGordon Ross  * Allocate a new opipe and return it, or NULL, in which case
41*68b2bbf2SGordon Ross  * the caller will report "internal error".
42*68b2bbf2SGordon Ross  */
43*68b2bbf2SGordon Ross static smb_opipe_t *
44*68b2bbf2SGordon Ross smb_opipe_alloc(smb_request_t *sr)
459fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States {
46*68b2bbf2SGordon Ross 	smb_server_t	*sv = sr->sr_server;
479fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_opipe_t	*opipe;
48*68b2bbf2SGordon Ross 	ksocket_t	sock;
49*68b2bbf2SGordon Ross 
50*68b2bbf2SGordon Ross 	if (ksocket_socket(&sock, AF_UNIX, SOCK_STREAM, 0,
51*68b2bbf2SGordon Ross 	    KSOCKET_SLEEP, sr->user_cr) != 0)
52*68b2bbf2SGordon Ross 		return (NULL);
539fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
548622ec45SGordon Ross 	opipe = kmem_cache_alloc(smb_cache_opipe, KM_SLEEP);
559fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
569fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	bzero(opipe, sizeof (smb_opipe_t));
579fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	mutex_init(&opipe->p_mutex, NULL, MUTEX_DEFAULT, NULL);
589fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	cv_init(&opipe->p_cv, NULL, CV_DEFAULT, NULL);
599fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	opipe->p_magic = SMB_OPIPE_MAGIC;
609fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	opipe->p_server = sv;
61*68b2bbf2SGordon Ross 	opipe->p_refcnt = 1;
62*68b2bbf2SGordon Ross 	opipe->p_socket = sock;
639fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
649fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	return (opipe);
659fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
669fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
67*68b2bbf2SGordon Ross /*
68*68b2bbf2SGordon Ross  * Destroy an opipe.  This is normally called from smb_ofile_delete
69*68b2bbf2SGordon Ross  * when the ofile has no more references and is about to be free'd.
70*68b2bbf2SGordon Ross  * This is also called here in error handling code paths, before
71*68b2bbf2SGordon Ross  * the opipe is installed under an ofile.
72*68b2bbf2SGordon Ross  */
739fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States void
749fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States smb_opipe_dealloc(smb_opipe_t *opipe)
759fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States {
769fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	smb_server_t *sv;
779fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
789fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	SMB_OPIPE_VALID(opipe);
799fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	sv = opipe->p_server;
809fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	SMB_SERVER_VALID(sv);
819fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
82*68b2bbf2SGordon Ross 	/*
83*68b2bbf2SGordon Ross 	 * This is called in the error path when opening,
84*68b2bbf2SGordon Ross 	 * in which case we close the socket here.
85*68b2bbf2SGordon Ross 	 */
86*68b2bbf2SGordon Ross 	if (opipe->p_socket != NULL)
87*68b2bbf2SGordon Ross 		(void) ksocket_close(opipe->p_socket, zone_kcred());
889fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
899fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	opipe->p_magic = (uint32_t)~SMB_OPIPE_MAGIC;
909fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	cv_destroy(&opipe->p_cv);
919fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	mutex_destroy(&opipe->p_mutex);
929fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
938622ec45SGordon Ross 	kmem_cache_free(smb_cache_opipe, opipe);
949fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States }
959fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
963db3f65cSamw /*
97*68b2bbf2SGordon Ross  * Helper for open: build pipe name and connect.
98*68b2bbf2SGordon Ross  */
99*68b2bbf2SGordon Ross static int
100*68b2bbf2SGordon Ross smb_opipe_connect(smb_request_t *sr, smb_opipe_t *opipe)
101*68b2bbf2SGordon Ross {
102*68b2bbf2SGordon Ross 	struct sockaddr_un saddr;
103*68b2bbf2SGordon Ross 	smb_arg_open_t	*op = &sr->sr_open;
104*68b2bbf2SGordon Ross 	const char *name;
105*68b2bbf2SGordon Ross 	int rc;
106*68b2bbf2SGordon Ross 
107*68b2bbf2SGordon Ross 	name = op->fqi.fq_path.pn_path;
108*68b2bbf2SGordon Ross 	name += strspn(name, "\\");
109*68b2bbf2SGordon Ross 	if (smb_strcasecmp(name, "PIPE", 4) == 0) {
110*68b2bbf2SGordon Ross 		name += 4;
111*68b2bbf2SGordon Ross 		name += strspn(name, "\\");
112*68b2bbf2SGordon Ross 	}
113*68b2bbf2SGordon Ross 	(void) strlcpy(opipe->p_name, name, SMB_OPIPE_MAXNAME);
114*68b2bbf2SGordon Ross 	(void) smb_strlwr(opipe->p_name);
115*68b2bbf2SGordon Ross 
116*68b2bbf2SGordon Ross 	bzero(&saddr, sizeof (saddr));
117*68b2bbf2SGordon Ross 	saddr.sun_family = AF_UNIX;
118*68b2bbf2SGordon Ross 	(void) snprintf(saddr.sun_path, sizeof (saddr.sun_path),
119*68b2bbf2SGordon Ross 	    "%s/%s", SMB_PIPE_DIR, opipe->p_name);
120*68b2bbf2SGordon Ross 	rc = ksocket_connect(opipe->p_socket, (struct sockaddr *)&saddr,
121*68b2bbf2SGordon Ross 	    sizeof (saddr), sr->user_cr);
122*68b2bbf2SGordon Ross 
123*68b2bbf2SGordon Ross 	return (rc);
124*68b2bbf2SGordon Ross }
125*68b2bbf2SGordon Ross 
126*68b2bbf2SGordon Ross /*
127*68b2bbf2SGordon Ross  * Helper for open: encode and send the user info.
128*68b2bbf2SGordon Ross  *
129*68b2bbf2SGordon Ross  * We send information about this client + user to the
130*68b2bbf2SGordon Ross  * pipe service so it can use it for access checks.
131*68b2bbf2SGordon Ross  * The service MAY deny the open based on this info,
132*68b2bbf2SGordon Ross  * (i.e. anonymous session trying to open a pipe that
133*68b2bbf2SGordon Ross  * requires authentication) in which case we will read
134*68b2bbf2SGordon Ross  * an error status from the service and return that.
135*68b2bbf2SGordon Ross  */
136*68b2bbf2SGordon Ross static void
137*68b2bbf2SGordon Ross smb_opipe_send_userinfo(smb_request_t *sr, smb_opipe_t *opipe,
138*68b2bbf2SGordon Ross     smb_error_t *errp)
139*68b2bbf2SGordon Ross {
140*68b2bbf2SGordon Ross 	XDR xdrs;
141*68b2bbf2SGordon Ross 	smb_netuserinfo_t nui;
142*68b2bbf2SGordon Ross 	smb_pipehdr_t phdr;
143*68b2bbf2SGordon Ross 	char *buf;
144*68b2bbf2SGordon Ross 	uint32_t buflen;
145*68b2bbf2SGordon Ross 	uint32_t status;
146*68b2bbf2SGordon Ross 	size_t iocnt = 0;
147*68b2bbf2SGordon Ross 	int rc;
148*68b2bbf2SGordon Ross 
149*68b2bbf2SGordon Ross 	/*
150*68b2bbf2SGordon Ross 	 * Any errors building the XDR message etc.
151*68b2bbf2SGordon Ross 	 */
152*68b2bbf2SGordon Ross 	errp->status = NT_STATUS_INTERNAL_ERROR;
153*68b2bbf2SGordon Ross 
154*68b2bbf2SGordon Ross 	smb_user_netinfo_init(sr->uid_user, &nui);
155*68b2bbf2SGordon Ross 	phdr.ph_magic = SMB_PIPE_HDR_MAGIC;
156*68b2bbf2SGordon Ross 	phdr.ph_uilen = xdr_sizeof(smb_netuserinfo_xdr, &nui);
157*68b2bbf2SGordon Ross 
158*68b2bbf2SGordon Ross 	buflen = sizeof (phdr) + phdr.ph_uilen;
159*68b2bbf2SGordon Ross 	buf = kmem_alloc(buflen, KM_SLEEP);
160*68b2bbf2SGordon Ross 
161*68b2bbf2SGordon Ross 	bcopy(&phdr, buf, sizeof (phdr));
162*68b2bbf2SGordon Ross 	xdrmem_create(&xdrs, buf + sizeof (phdr),
163*68b2bbf2SGordon Ross 	    buflen - (sizeof (phdr)), XDR_ENCODE);
164*68b2bbf2SGordon Ross 	if (!smb_netuserinfo_xdr(&xdrs, &nui))
165*68b2bbf2SGordon Ross 		goto out;
166*68b2bbf2SGordon Ross 
167*68b2bbf2SGordon Ross 	/*
168*68b2bbf2SGordon Ross 	 * If we fail sending the netuserinfo or recv'ing the
169*68b2bbf2SGordon Ross 	 * status reponse, we have probably run into the limit
170*68b2bbf2SGordon Ross 	 * on the number of open pipes.  That's this status:
171*68b2bbf2SGordon Ross 	 */
172*68b2bbf2SGordon Ross 	errp->status = NT_STATUS_PIPE_NOT_AVAILABLE;
173*68b2bbf2SGordon Ross 
174*68b2bbf2SGordon Ross 	rc = ksocket_send(opipe->p_socket, buf, buflen, 0,
175*68b2bbf2SGordon Ross 	    &iocnt, sr->user_cr);
176*68b2bbf2SGordon Ross 	if (rc == 0 && iocnt != buflen)
177*68b2bbf2SGordon Ross 		rc = EIO;
178*68b2bbf2SGordon Ross 	if (rc != 0)
179*68b2bbf2SGordon Ross 		goto out;
180*68b2bbf2SGordon Ross 
181*68b2bbf2SGordon Ross 	rc = ksocket_recv(opipe->p_socket, &status, sizeof (status), 0,
182*68b2bbf2SGordon Ross 	    &iocnt, sr->user_cr);
183*68b2bbf2SGordon Ross 	if (rc != 0 || iocnt != sizeof (status))
184*68b2bbf2SGordon Ross 		goto out;
185*68b2bbf2SGordon Ross 
186*68b2bbf2SGordon Ross 	/*
187*68b2bbf2SGordon Ross 	 * Return the status we read from the pipe service,
188*68b2bbf2SGordon Ross 	 * normally NT_STATUS_SUCCESS, but could be something
189*68b2bbf2SGordon Ross 	 * else like NT_STATUS_ACCESS_DENIED.
190*68b2bbf2SGordon Ross 	 */
191*68b2bbf2SGordon Ross 	errp->status = status;
192*68b2bbf2SGordon Ross 
193*68b2bbf2SGordon Ross out:
194*68b2bbf2SGordon Ross 	xdr_destroy(&xdrs);
195*68b2bbf2SGordon Ross 	kmem_free(buf, buflen);
196*68b2bbf2SGordon Ross 	smb_user_netinfo_fini(&nui);
197*68b2bbf2SGordon Ross }
198*68b2bbf2SGordon Ross 
199*68b2bbf2SGordon Ross /*
2003db3f65cSamw  * smb_opipe_open
2013db3f65cSamw  *
202*68b2bbf2SGordon Ross  * Open an RPC named pipe. This routine should be called if
2033db3f65cSamw  * a file open is requested on a share of type STYPE_IPC.
2043db3f65cSamw  * If we recognize the pipe, we setup a new ofile.
2053db3f65cSamw  *
206*68b2bbf2SGordon Ross  * Returns 0 on success, Otherwise an NT status code.
2073db3f65cSamw  */
2083db3f65cSamw int
209*68b2bbf2SGordon Ross smb_opipe_open(smb_request_t *sr, uint32_t uniqid)
2103db3f65cSamw {
211148c5f43SAlan Wright 	smb_arg_open_t	*op = &sr->sr_open;
212*68b2bbf2SGordon Ross 	smb_ofile_t *ofile;
2133db3f65cSamw 	smb_opipe_t *opipe;
2143db3f65cSamw 	smb_error_t err;
2153db3f65cSamw 
216*68b2bbf2SGordon Ross 	opipe = smb_opipe_alloc(sr);
217*68b2bbf2SGordon Ross 	if (opipe == NULL)
218*68b2bbf2SGordon Ross 		return (NT_STATUS_INTERNAL_ERROR);
2193db3f65cSamw 
220*68b2bbf2SGordon Ross 	if (smb_opipe_connect(sr, opipe) != 0) {
221*68b2bbf2SGordon Ross 		smb_opipe_dealloc(opipe);
2228b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 		return (NT_STATUS_OBJECT_NAME_NOT_FOUND);
2238b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 	}
2248b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States 
225*68b2bbf2SGordon Ross 	smb_opipe_send_userinfo(sr, opipe, &err);
226*68b2bbf2SGordon Ross 	if (err.status != 0) {
227*68b2bbf2SGordon Ross 		smb_opipe_dealloc(opipe);
228*68b2bbf2SGordon Ross 		return (err.status);
229*68b2bbf2SGordon Ross 	}
230*68b2bbf2SGordon Ross 
231*68b2bbf2SGordon Ross 	/*
232*68b2bbf2SGordon Ross 	 * Note: If smb_ofile_open succeeds, the new ofile is
233*68b2bbf2SGordon Ross 	 * in the FID lists can can be used by I/O requests.
234*68b2bbf2SGordon Ross 	 */
235*68b2bbf2SGordon Ross 	op->create_options = 0;
236*68b2bbf2SGordon Ross 	op->pipe = opipe;
237*68b2bbf2SGordon Ross 	ofile = smb_ofile_open(sr, NULL, op,
238*68b2bbf2SGordon Ross 	    SMB_FTYPE_MESG_PIPE, uniqid, &err);
239*68b2bbf2SGordon Ross 	op->pipe = NULL;
240*68b2bbf2SGordon Ross 	if (ofile == NULL) {
241*68b2bbf2SGordon Ross 		smb_opipe_dealloc(opipe);
242*68b2bbf2SGordon Ross 		return (err.status);
243*68b2bbf2SGordon Ross 	}
244*68b2bbf2SGordon Ross 
245*68b2bbf2SGordon Ross 	/* An "up" pointer, for debug. */
246*68b2bbf2SGordon Ross 	opipe->p_ofile = ofile;
247*68b2bbf2SGordon Ross 
2483db3f65cSamw 	op->dsize = 0x01000;
2493db3f65cSamw 	op->dattr = FILE_ATTRIBUTE_NORMAL;
2503db3f65cSamw 	op->ftype = SMB_FTYPE_MESG_PIPE;
2513db3f65cSamw 	op->action_taken = SMB_OACT_LOCK | SMB_OACT_OPENED; /* 0x8001 */
2523db3f65cSamw 	op->devstate = SMB_PIPE_READMODE_MESSAGE
2533db3f65cSamw 	    | SMB_PIPE_TYPE_MESSAGE
2543db3f65cSamw 	    | SMB_PIPE_UNLIMITED_INSTANCES; /* 0x05ff */
255*68b2bbf2SGordon Ross 	op->fileid = ofile->f_fid;
2563db3f65cSamw 
257*68b2bbf2SGordon Ross 	sr->smb_fid = ofile->f_fid;
258*68b2bbf2SGordon Ross 	sr->fid_ofile = ofile;
2593db3f65cSamw 
2603db3f65cSamw 	return (NT_STATUS_SUCCESS);
2613db3f65cSamw }
2623db3f65cSamw 
2633db3f65cSamw /*
2643db3f65cSamw  * smb_opipe_close
2653db3f65cSamw  *
266*68b2bbf2SGordon Ross  * Called by smb_ofile_close for pipes.
267*68b2bbf2SGordon Ross  *
268*68b2bbf2SGordon Ross  * Note: ksocket_close may block while waiting for
269*68b2bbf2SGordon Ross  * any I/O threads with a hold to get out.
2703db3f65cSamw  */
2713db3f65cSamw void
2723db3f65cSamw smb_opipe_close(smb_ofile_t *of)
2733db3f65cSamw {
2743db3f65cSamw 	smb_opipe_t *opipe;
275*68b2bbf2SGordon Ross 	ksocket_t sock;
2763db3f65cSamw 
277*68b2bbf2SGordon Ross 	ASSERT(of->f_state == SMB_OFILE_STATE_CLOSING);
2783db3f65cSamw 	ASSERT(of->f_ftype == SMB_FTYPE_MESG_PIPE);
2793db3f65cSamw 	opipe = of->f_pipe;
2809fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	SMB_OPIPE_VALID(opipe);
2819fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
282*68b2bbf2SGordon Ross 	mutex_enter(&opipe->p_mutex);
283*68b2bbf2SGordon Ross 	sock = opipe->p_socket;
284*68b2bbf2SGordon Ross 	opipe->p_socket = NULL;
285*68b2bbf2SGordon Ross 	mutex_exit(&opipe->p_mutex);
2863db3f65cSamw 
287*68b2bbf2SGordon Ross 	(void) ksocket_shutdown(sock, SHUT_RDWR, of->f_cr);
288*68b2bbf2SGordon Ross 	(void) ksocket_close(sock, of->f_cr);
2893db3f65cSamw }
2903db3f65cSamw 
2913db3f65cSamw /*
2923db3f65cSamw  * smb_opipe_write
2933db3f65cSamw  *
2943db3f65cSamw  * Write RPC request data to the pipe.  The client should call smb_opipe_read
2953db3f65cSamw  * to complete the exchange and obtain the RPC response.
2963db3f65cSamw  *
2973db3f65cSamw  * Returns 0 on success or an errno on failure.
2983db3f65cSamw  */
2993db3f65cSamw int
3003db3f65cSamw smb_opipe_write(smb_request_t *sr, struct uio *uio)
3013db3f65cSamw {
302*68b2bbf2SGordon Ross 	struct nmsghdr msghdr;
303*68b2bbf2SGordon Ross 	smb_ofile_t *ofile;
3043db3f65cSamw 	smb_opipe_t *opipe;
305*68b2bbf2SGordon Ross 	ksocket_t sock;
306*68b2bbf2SGordon Ross 	size_t sent = 0;
307*68b2bbf2SGordon Ross 	int rc = 0;
3083db3f65cSamw 
309*68b2bbf2SGordon Ross 	ofile = sr->fid_ofile;
310*68b2bbf2SGordon Ross 	ASSERT(ofile->f_ftype == SMB_FTYPE_MESG_PIPE);
311*68b2bbf2SGordon Ross 	opipe = ofile->f_pipe;
3129fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	SMB_OPIPE_VALID(opipe);
3133db3f65cSamw 
314*68b2bbf2SGordon Ross 	mutex_enter(&opipe->p_mutex);
315*68b2bbf2SGordon Ross 	sock = opipe->p_socket;
316*68b2bbf2SGordon Ross 	if (sock != NULL)
317*68b2bbf2SGordon Ross 		ksocket_hold(sock);
318*68b2bbf2SGordon Ross 	mutex_exit(&opipe->p_mutex);
319*68b2bbf2SGordon Ross 	if (sock == NULL)
3203db3f65cSamw 		return (EBADF);
321*68b2bbf2SGordon Ross 
322*68b2bbf2SGordon Ross 	bzero(&msghdr, sizeof (msghdr));
323*68b2bbf2SGordon Ross 	msghdr.msg_iov = uio->uio_iov;
324*68b2bbf2SGordon Ross 	msghdr.msg_iovlen = uio->uio_iovcnt;
325*68b2bbf2SGordon Ross 
326*68b2bbf2SGordon Ross 	/*
327*68b2bbf2SGordon Ross 	 * This should block until we've sent it all,
328*68b2bbf2SGordon Ross 	 * or given up due to errors (pipe closed).
329*68b2bbf2SGordon Ross 	 */
330*68b2bbf2SGordon Ross 	while (uio->uio_resid > 0) {
331*68b2bbf2SGordon Ross 		rc = ksocket_sendmsg(sock, &msghdr, 0, &sent, ofile->f_cr);
332*68b2bbf2SGordon Ross 		if (rc != 0)
333*68b2bbf2SGordon Ross 			break;
334*68b2bbf2SGordon Ross 		uio->uio_resid -= sent;
3353db3f65cSamw 	}
3363db3f65cSamw 
337*68b2bbf2SGordon Ross 	ksocket_rele(sock);
3383db3f65cSamw 
339*68b2bbf2SGordon Ross 	return (rc);
3403db3f65cSamw }
3413db3f65cSamw 
3423db3f65cSamw /*
3433db3f65cSamw  * smb_opipe_read
3443db3f65cSamw  *
345*68b2bbf2SGordon Ross  * This interface may be called from smb_opipe_transact (write, read)
346*68b2bbf2SGordon Ross  * or from smb_read / smb2_read to get the rest of an RPC response.
347*68b2bbf2SGordon Ross  * The response data (and length) are returned via the uio.
3483db3f65cSamw  */
3493db3f65cSamw int
3503db3f65cSamw smb_opipe_read(smb_request_t *sr, struct uio *uio)
3513db3f65cSamw {
352*68b2bbf2SGordon Ross 	struct nmsghdr msghdr;
353*68b2bbf2SGordon Ross 	smb_ofile_t *ofile;
3543db3f65cSamw 	smb_opipe_t *opipe;
355*68b2bbf2SGordon Ross 	ksocket_t sock;
356*68b2bbf2SGordon Ross 	size_t recvcnt = 0;
3573db3f65cSamw 	int rc;
3583db3f65cSamw 
359*68b2bbf2SGordon Ross 	ofile = sr->fid_ofile;
360*68b2bbf2SGordon Ross 	ASSERT(ofile->f_ftype == SMB_FTYPE_MESG_PIPE);
361*68b2bbf2SGordon Ross 	opipe = ofile->f_pipe;
3629fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	SMB_OPIPE_VALID(opipe);
3639fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
364*68b2bbf2SGordon Ross 	mutex_enter(&opipe->p_mutex);
365*68b2bbf2SGordon Ross 	sock = opipe->p_socket;
366*68b2bbf2SGordon Ross 	if (sock != NULL)
367*68b2bbf2SGordon Ross 		ksocket_hold(sock);
368*68b2bbf2SGordon Ross 	mutex_exit(&opipe->p_mutex);
369*68b2bbf2SGordon Ross 	if (sock == NULL)
3703db3f65cSamw 		return (EBADF);
3713db3f65cSamw 
372*68b2bbf2SGordon Ross 	bzero(&msghdr, sizeof (msghdr));
373*68b2bbf2SGordon Ross 	msghdr.msg_iov = uio->uio_iov;
374*68b2bbf2SGordon Ross 	msghdr.msg_iovlen = uio->uio_iovcnt;
3759fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 
3763db3f65cSamw 	/*
377*68b2bbf2SGordon Ross 	 * This should block only if there's no data.
378*68b2bbf2SGordon Ross 	 * A single call to recvmsg does just that.
379*68b2bbf2SGordon Ross 	 * (Intentionaly no recv loop here.)
3803db3f65cSamw 	 */
381*68b2bbf2SGordon Ross 	rc = ksocket_recvmsg(sock, &msghdr, 0,
382*68b2bbf2SGordon Ross 	    &recvcnt, ofile->f_cr);
383*68b2bbf2SGordon Ross 	if (rc != 0)
384*68b2bbf2SGordon Ross 		goto out;
3853db3f65cSamw 
386*68b2bbf2SGordon Ross 	if (recvcnt == 0) {
387*68b2bbf2SGordon Ross 		/* Other side closed. */
388*68b2bbf2SGordon Ross 		rc = EPIPE;
389*68b2bbf2SGordon Ross 		goto out;
3903db3f65cSamw 	}
391*68b2bbf2SGordon Ross 	uio->uio_resid -= recvcnt;
3923db3f65cSamw 
3939fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	/*
394*68b2bbf2SGordon Ross 	 * If we filled the user's buffer,
395*68b2bbf2SGordon Ross 	 * find out if there's more data.
3969fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 	 */
397*68b2bbf2SGordon Ross 	if (uio->uio_resid == 0) {
398*68b2bbf2SGordon Ross 		int rc2, nread, trval;
399*68b2bbf2SGordon Ross 		rc2 = ksocket_ioctl(sock, FIONREAD, (intptr_t)&nread,
400*68b2bbf2SGordon Ross 		    &trval, ofile->f_cr);
401*68b2bbf2SGordon Ross 		if (rc2 == 0 && nread != 0)
402*68b2bbf2SGordon Ross 			rc = E2BIG;	/* more data */
403*68b2bbf2SGordon Ross 	}
404*68b2bbf2SGordon Ross 
405*68b2bbf2SGordon Ross out:
406*68b2bbf2SGordon Ross 	ksocket_rele(sock);
407*68b2bbf2SGordon Ross 
408*68b2bbf2SGordon Ross 	return (rc);
4093db3f65cSamw }
410