xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_read.c (revision dc20a3024900c47dd2ee44b9707e6df38f7d62a5)
1da6c28aaSamw /*
2da6c28aaSamw  * CDDL HEADER START
3da6c28aaSamw  *
4da6c28aaSamw  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
7da6c28aaSamw  *
8da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw  * See the License for the specific language governing permissions
11da6c28aaSamw  * and limitations under the License.
12da6c28aaSamw  *
13da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw  *
19da6c28aaSamw  * CDDL HEADER END
20da6c28aaSamw  */
21da6c28aaSamw /*
22*dc20a302Sas200622  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23da6c28aaSamw  * Use is subject to license terms.
24da6c28aaSamw  */
25da6c28aaSamw 
26da6c28aaSamw #pragma ident	"%Z%%M%	%I%	%E% SMI"
27da6c28aaSamw 
28da6c28aaSamw #include <sys/syslog.h>
29da6c28aaSamw #include <smbsrv/smb_incl.h>
30da6c28aaSamw #include <smbsrv/smb_fsops.h>
31da6c28aaSamw 
32da6c28aaSamw 
33da6c28aaSamw typedef struct smb_read_param {
34da6c28aaSamw 	uint64_t r_offset;
35da6c28aaSamw 	uint16_t r_count;
36da6c28aaSamw 	uint16_t r_mincnt;
37da6c28aaSamw } smb_read_param_t;
38da6c28aaSamw 
39da6c28aaSamw 
40da6c28aaSamw int smb_common_read(struct smb_request *sr, smb_read_param_t *param);
41da6c28aaSamw 
42da6c28aaSamw 
43da6c28aaSamw /*
44da6c28aaSamw  * Read bytes from a file or named pipe (SMB Core).
45da6c28aaSamw  *
46da6c28aaSamw  * The requested count specifies the number of bytes desired.  Offset
47da6c28aaSamw  * is limited to 32 bits, so this client request is inappropriate for
48da6c28aaSamw  * files with 64 bit offsets.
49da6c28aaSamw  *
50da6c28aaSamw  * On return, count is the number of bytes actually being returned, which
51da6c28aaSamw  * may be less than the count requested only if a read specifies bytes
52da6c28aaSamw  * beyond the current file size.  In this case only the bytes that exist
53da6c28aaSamw  * are returned.  A read completely beyond the end of file results in a
54da6c28aaSamw  * response of length zero.  This is the only circumstance when a zero
55da6c28aaSamw  * length response is generated.  A count returned which is less than the
56da6c28aaSamw  * count requested is the end of file indicator.
57da6c28aaSamw  */
58da6c28aaSamw int
59da6c28aaSamw smb_com_read(struct smb_request *sr)
60da6c28aaSamw {
61da6c28aaSamw 	smb_read_param_t param;
62da6c28aaSamw 	uint32_t off_low;
63da6c28aaSamw 	uint16_t remcnt;
64da6c28aaSamw 	int rc;
65da6c28aaSamw 
66da6c28aaSamw 	rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid,
67da6c28aaSamw 	    &param.r_count, &off_low, &remcnt);
68da6c28aaSamw 	if (rc != 0) {
69da6c28aaSamw 		smbsr_decode_error(sr);
70da6c28aaSamw 		/* NOTREACHED */
71da6c28aaSamw 	}
72da6c28aaSamw 
73da6c28aaSamw 	param.r_offset = (uint64_t)off_low;
74da6c28aaSamw 	param.r_mincnt = 0;
75da6c28aaSamw 
76da6c28aaSamw 	sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
77da6c28aaSamw 	if (sr->fid_ofile == NULL) {
78*dc20a302Sas200622 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
79da6c28aaSamw 		/* NOTREACHED */
80da6c28aaSamw 	}
81da6c28aaSamw 
82da6c28aaSamw 	if ((rc = smb_common_read(sr, &param)) != 0) {
83*dc20a302Sas200622 		smbsr_errno(sr, rc);
84da6c28aaSamw 		/* NOTREACHED */
85da6c28aaSamw 	}
86da6c28aaSamw 
87da6c28aaSamw 	smbsr_encode_result(sr, 5, VAR_BCC, "bw8.wbwC",
88da6c28aaSamw 	    5, param.r_count, VAR_BCC, 0x01, param.r_count, &sr->raw_data);
89da6c28aaSamw 
90da6c28aaSamw 	return (SDRC_NORMAL_REPLY);
91da6c28aaSamw }
92da6c28aaSamw 
93da6c28aaSamw /*
94da6c28aaSamw  * Lock and read bytes from a file (SMB Core Plus).  The SmbLockAndRead/
95da6c28aaSamw  * SmbLockAndWrite sub-dialect is only valid on disk files: reject any
96da6c28aaSamw  * attempt to use it on non-disk shares.
97da6c28aaSamw  *
98da6c28aaSamw  * The requested count specifies the number of bytes desired.  Offset
99da6c28aaSamw  * specifies the offset in the file of the first byte to be locked then
100da6c28aaSamw  * read. Note that offset is limited to 32 bits, so this client request
101da6c28aaSamw  * is inappropriate for files with 64 bit offsets.
102da6c28aaSamw  *
103da6c28aaSamw  * As with SMB_LOCK_BYTE_RANGE request, if the lock cannot be granted
104da6c28aaSamw  * immediately an error should be returned to the client.  If an error
105da6c28aaSamw  * occurs on the lock, the bytes should not be read.
106da6c28aaSamw  *
107da6c28aaSamw  * On return, count is the number of bytes actually being returned, which
108da6c28aaSamw  * may be less than the count requested only if a read specifies bytes
109da6c28aaSamw  * beyond the current file size.  In this case only the bytes that exist
110da6c28aaSamw  * are returned.  A read completely beyond the end of file results in a
111da6c28aaSamw  * response of length zero.  This is the only circumstance when a zero
112da6c28aaSamw  * length response is generated.  A count returned which is less than the
113da6c28aaSamw  * count requested is the end of file indicator.
114da6c28aaSamw  */
115da6c28aaSamw int
116da6c28aaSamw smb_com_lock_and_read(struct smb_request *sr)
117da6c28aaSamw {
118da6c28aaSamw 	smb_read_param_t param;
119da6c28aaSamw 	uint16_t remcnt;
120da6c28aaSamw 	uint32_t off_low;
121da6c28aaSamw 	DWORD result;
122da6c28aaSamw 	int rc;
123da6c28aaSamw 
124da6c28aaSamw 	if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) {
125*dc20a302Sas200622 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERRnoaccess);
126da6c28aaSamw 		/* NOTREACHED */
127da6c28aaSamw 	}
128da6c28aaSamw 
129da6c28aaSamw 	rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid,
130da6c28aaSamw 	    &param.r_count, &off_low, &remcnt);
131da6c28aaSamw 	if (rc != 0) {
132da6c28aaSamw 		smbsr_decode_error(sr);
133da6c28aaSamw 		/* NOTREACHED */
134da6c28aaSamw 	}
135da6c28aaSamw 
136da6c28aaSamw 	param.r_offset = (uint64_t)off_low;
137da6c28aaSamw 	param.r_mincnt = 0;
138da6c28aaSamw 
139da6c28aaSamw 	sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
140da6c28aaSamw 	if (sr->fid_ofile == NULL) {
141*dc20a302Sas200622 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
142da6c28aaSamw 		/* NOTREACHED */
143da6c28aaSamw 	}
144da6c28aaSamw 
145da6c28aaSamw 	result = smb_lock_range(sr, sr->fid_ofile, param.r_offset,
14655bf511dSas200622 	    (uint64_t)param.r_count, UINT_MAX, SMB_LOCK_TYPE_READWRITE);
147da6c28aaSamw 	if (result != NT_STATUS_SUCCESS) {
148*dc20a302Sas200622 		smb_lock_range_error(sr, result);
149da6c28aaSamw 	}
150da6c28aaSamw 
151da6c28aaSamw 	if ((rc = smb_common_read(sr, &param)) != 0) {
152*dc20a302Sas200622 		smbsr_errno(sr, rc);
153da6c28aaSamw 		/* NOTREACHED */
154da6c28aaSamw 	}
155da6c28aaSamw 
156da6c28aaSamw 	smbsr_encode_result(sr, 5, VAR_BCC, "bw8.wbwC",
157da6c28aaSamw 	    5, param.r_count, VAR_BCC, 0x1, param.r_count, &sr->raw_data);
158da6c28aaSamw 
159da6c28aaSamw 	return (SDRC_NORMAL_REPLY);
160da6c28aaSamw }
161da6c28aaSamw 
162da6c28aaSamw /*
163da6c28aaSamw  * The SMB_COM_READ_RAW protocol is a negotiated option introduced in
164da6c28aaSamw  * SMB Core Plus to maximize performance when reading a large block
165da6c28aaSamw  * of data from a server.  This request was extended in LM 0.12 to
166da6c28aaSamw  * support 64-bit offsets; the server can indicate support by setting
167da6c28aaSamw  * CAP_LARGE_FILES in the negotiated capabilities.
168da6c28aaSamw  *
169da6c28aaSamw  * The client must guarantee that there is (and will be) no other request
170da6c28aaSamw  * to the server for the duration of the SMB_COM_READ_RAW, since the
171da6c28aaSamw  * server response has no header or trailer. To help ensure that there
172da6c28aaSamw  * are no interruptions, we block all I/O for the session during read raw.
173da6c28aaSamw  *
174da6c28aaSamw  * If this is the first SMB request received since we sent an oplock break
175da6c28aaSamw  * to this client, we don't know if it's safe to send the raw data because
176da6c28aaSamw  * the requests may have crossed on the wire and the client may have
177da6c28aaSamw  * interpreted the oplock break as part of the raw data. To avoid problems,
178da6c28aaSamw  * we send a zero length session packet, which will force the client to
179da6c28aaSamw  * retry the read.
180da6c28aaSamw  *
181da6c28aaSamw  * Read errors are handled by sending a zero length response.
182da6c28aaSamw  */
183da6c28aaSamw int
184da6c28aaSamw smb_com_read_raw(struct smb_request *sr)
185da6c28aaSamw {
186da6c28aaSamw 	smb_read_param_t	param;
187da6c28aaSamw 	smb_node_t		*node;
188da6c28aaSamw 	uint32_t		off_low;
189da6c28aaSamw 	uint32_t		off_high;
190da6c28aaSamw 	uint32_t		timeout;
191da6c28aaSamw 	int			rc;
192da6c28aaSamw 
193da6c28aaSamw 	switch (sr->session->s_state) {
194da6c28aaSamw 	case SMB_SESSION_STATE_NEGOTIATED:
195da6c28aaSamw 		if (sr->smb_wct == 8) {
196da6c28aaSamw 			rc = smbsr_decode_vwv(sr, "wlwwl2.", &sr->smb_fid,
197da6c28aaSamw 			    &off_low, &param.r_count, &param.r_mincnt,
198da6c28aaSamw 			    &timeout);
199da6c28aaSamw 			param.r_offset = (uint64_t)off_low;
200da6c28aaSamw 		} else {
201da6c28aaSamw 			rc = smbsr_decode_vwv(sr, "wlwwl2.l", &sr->smb_fid,
202da6c28aaSamw 			    &off_low, &param.r_count, &param.r_mincnt, &timeout,
203da6c28aaSamw 			    &off_high);
204da6c28aaSamw 			param.r_offset = ((uint64_t)off_high << 32) | off_low;
205da6c28aaSamw 		}
206da6c28aaSamw 
207da6c28aaSamw 		if (rc != 0) {
208da6c28aaSamw 			smbsr_decode_error(sr);
209da6c28aaSamw 			/* NOTREACHED */
210da6c28aaSamw 		}
211da6c28aaSamw 
212da6c28aaSamw 		sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree,
213da6c28aaSamw 		    sr->smb_fid);
214da6c28aaSamw 		if (sr->fid_ofile == NULL) {
215*dc20a302Sas200622 			smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
216da6c28aaSamw 			    ERRDOS, ERRbadfid);
217da6c28aaSamw 			/* NOTREACHED */
218da6c28aaSamw 		}
219da6c28aaSamw 
220da6c28aaSamw 		rc = smb_common_read(sr, &param);
221da6c28aaSamw 		/*
222da6c28aaSamw 		 * XXX Do we need to handle errors here?  What if we have an
223da6c28aaSamw 		 * access error (either permissions or range lock violations?
224da6c28aaSamw 		 */
225da6c28aaSamw 		if (STYPE_ISDSK(sr->tid_tree->t_res_type)) {
226da6c28aaSamw 			node = sr->fid_ofile->f_node;
227da6c28aaSamw 			if (node->n_oplock.op_flags & OPLOCK_FLAG_BREAKING) {
228da6c28aaSamw 				rc = EAGAIN;
229da6c28aaSamw 			}
230da6c28aaSamw 		}
231da6c28aaSamw 
232da6c28aaSamw 		if (rc != 0) {
233da6c28aaSamw 			(void) smb_session_send(sr->session, 0, NULL);
234da6c28aaSamw 			m_freem(sr->raw_data.chain);
235da6c28aaSamw 			sr->raw_data.chain = 0;
236da6c28aaSamw 		} else {
237da6c28aaSamw 			(void) smb_session_send(sr->session, 0, &sr->raw_data);
238da6c28aaSamw 		}
239da6c28aaSamw 		return (SDRC_NO_REPLY);
240da6c28aaSamw 
241da6c28aaSamw 	case SMB_SESSION_STATE_OPLOCK_BREAKING:
242da6c28aaSamw 		(void) smb_session_send(sr->session, 0, NULL);
243da6c28aaSamw 		sr->session->s_state = SMB_SESSION_STATE_NEGOTIATED;
244da6c28aaSamw 		return (SDRC_NO_REPLY);
245da6c28aaSamw 
246da6c28aaSamw 	case SMB_SESSION_STATE_WRITE_RAW_ACTIVE:
247da6c28aaSamw 		ASSERT(0);
248da6c28aaSamw 		return (SDRC_DROP_VC);
249da6c28aaSamw 
250da6c28aaSamw 	case SMB_SESSION_STATE_TERMINATED:
251da6c28aaSamw 		ASSERT(0);
252da6c28aaSamw 		return (SDRC_NO_REPLY);
253da6c28aaSamw 
254da6c28aaSamw 	case SMB_SESSION_STATE_DISCONNECTED:
255da6c28aaSamw 		return (SDRC_NO_REPLY);
256da6c28aaSamw 
257da6c28aaSamw 	case SMB_SESSION_STATE_CONNECTED:
258da6c28aaSamw 	case SMB_SESSION_STATE_ESTABLISHED:
259da6c28aaSamw 	default:
260da6c28aaSamw 		ASSERT(0);
261da6c28aaSamw 		return (SDRC_DROP_VC);
262da6c28aaSamw 	}
263da6c28aaSamw }
264da6c28aaSamw 
265da6c28aaSamw /*
266da6c28aaSamw  * Read bytes from a file (SMB Core).  This request was extended in
267da6c28aaSamw  * LM 0.12 to support 64-bit offsets, indicated by sending a wct of
268da6c28aaSamw  * 12 and including additional offset information.
269da6c28aaSamw  */
270da6c28aaSamw int
271da6c28aaSamw smb_com_read_andx(struct smb_request *sr)
272da6c28aaSamw {
273da6c28aaSamw 	smb_read_param_t param;
274da6c28aaSamw 	uint32_t off_low;
275da6c28aaSamw 	uint32_t off_high;
276da6c28aaSamw 	uint16_t remcnt;
277da6c28aaSamw 	uint16_t offset2;
278da6c28aaSamw 	uint8_t secondary;
279da6c28aaSamw 	int rc;
280da6c28aaSamw 
281da6c28aaSamw 	if (sr->smb_wct == 12) {
282da6c28aaSamw 		rc = smbsr_decode_vwv(sr, "b3.wlw6.wl", &secondary,
283da6c28aaSamw 		    &sr->smb_fid, &off_low, &param.r_count, &remcnt, &off_high);
284da6c28aaSamw 
285da6c28aaSamw 		param.r_offset = ((uint64_t)off_high << 32) | off_low;
286da6c28aaSamw 	} else {
287da6c28aaSamw 		rc = smbsr_decode_vwv(sr, "b3.wlw6.w", &secondary,
288da6c28aaSamw 		    &sr->smb_fid, &off_low, &param.r_count, &remcnt);
289da6c28aaSamw 
290da6c28aaSamw 		param.r_offset = (uint64_t)off_low;
291da6c28aaSamw 	}
292da6c28aaSamw 
293da6c28aaSamw 	if (rc != 0) {
294da6c28aaSamw 		smbsr_decode_error(sr);
295da6c28aaSamw 		/* NOTREACHED */
296da6c28aaSamw 	}
297da6c28aaSamw 
298da6c28aaSamw 	param.r_mincnt = 0;
299da6c28aaSamw 
300da6c28aaSamw 	sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
301da6c28aaSamw 	if (sr->fid_ofile == NULL) {
302*dc20a302Sas200622 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
303da6c28aaSamw 		/* NOTREACHED */
304da6c28aaSamw 	}
305da6c28aaSamw 
306da6c28aaSamw 	if ((rc = smb_common_read(sr, &param)) != 0) {
307*dc20a302Sas200622 		smbsr_errno(sr, rc);
308da6c28aaSamw 		/* NOTREACHED */
309da6c28aaSamw 	}
310da6c28aaSamw 
311da6c28aaSamw 	/*
312da6c28aaSamw 	 * Ensure that the next response offset is zero
313da6c28aaSamw 	 * if there is no secondary command.
314da6c28aaSamw 	 */
315da6c28aaSamw 	offset2 = (secondary == 0xFF) ? 0 : param.r_count + 59;
316da6c28aaSamw 
317da6c28aaSamw 	/*
318da6c28aaSamw 	 * The STYPE_IPC response format is different.
319da6c28aaSamw 	 * The unknown value (2) may be to indicate that it
320da6c28aaSamw 	 * is a follow-up to an earlier RPC transaction.
321da6c28aaSamw 	 */
322da6c28aaSamw 	if (STYPE_ISIPC(sr->tid_tree->t_res_type)) {
323da6c28aaSamw 		smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.ww10.wbC",
324da6c28aaSamw 		    12,			/* wct */
325da6c28aaSamw 		    secondary,		/* Secondary andx command */
326da6c28aaSamw 		    offset2,		/* offset to next */
327da6c28aaSamw 		    0,			/* must be 0 */
328da6c28aaSamw 		    param.r_count,	/* data byte count */
329da6c28aaSamw 		    60,			/* Offset from start to data */
330da6c28aaSamw 		    VAR_BCC,		/* BCC marker */
331da6c28aaSamw 		    0x02,		/* unknown */
332da6c28aaSamw 		    &sr->raw_data);
333da6c28aaSamw 	} else {
334da6c28aaSamw 		smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.ww10.wC",
335da6c28aaSamw 		    12,			/* wct */
336da6c28aaSamw 		    secondary,		/* Secondary andx command */
337da6c28aaSamw 		    offset2,		/* offset to next */
338da6c28aaSamw 		    -1,			/* must be -1 */
339da6c28aaSamw 		    param.r_count,	/* data byte count */
340da6c28aaSamw 		    59,			/* Offset from start to data */
341da6c28aaSamw 		    VAR_BCC,		/* BCC marker */
342da6c28aaSamw 		    &sr->raw_data);
343da6c28aaSamw 	}
344da6c28aaSamw 
345da6c28aaSamw 	return (SDRC_NORMAL_REPLY);
346da6c28aaSamw }
347da6c28aaSamw 
348da6c28aaSamw /*
349da6c28aaSamw  * Common function for reading files or IPC/MSRPC named pipes.  All
350da6c28aaSamw  * protocol read functions should lookup the fid before calling this
351da6c28aaSamw  * function.  We can't move the fid lookup here because lock-and-read
352da6c28aaSamw  * requires the fid to do locking before attempting the read.
353da6c28aaSamw  *
354da6c28aaSamw  * Returns errno values.
355da6c28aaSamw  */
356da6c28aaSamw int
357da6c28aaSamw smb_common_read(struct smb_request *sr, smb_read_param_t *param)
358da6c28aaSamw {
359da6c28aaSamw 	smb_ofile_t *ofile = sr->fid_ofile;
360da6c28aaSamw 	smb_node_t *node;
361da6c28aaSamw 	struct vardata_block *vdb;
362da6c28aaSamw 	struct mbuf *top;
363da6c28aaSamw 	int rc;
364da6c28aaSamw 
365da6c28aaSamw 	vdb = kmem_alloc(sizeof (struct vardata_block), KM_SLEEP);
366da6c28aaSamw 	vdb->tag = 0;
367da6c28aaSamw 	vdb->uio.uio_iov = &vdb->iovec[0];
368da6c28aaSamw 	vdb->uio.uio_iovcnt = MAX_IOVEC;
369da6c28aaSamw 	vdb->uio.uio_resid = param->r_count;
37055bf511dSas200622 	vdb->uio.uio_loffset = (offset_t)param->r_offset;
371da6c28aaSamw 	vdb->uio.uio_segflg = UIO_SYSSPACE;
372da6c28aaSamw 
373da6c28aaSamw 	switch (sr->tid_tree->t_res_type & STYPE_MASK) {
374da6c28aaSamw 	case STYPE_DISKTREE:
375da6c28aaSamw 		node = ofile->f_node;
376da6c28aaSamw 
377da6c28aaSamw 		if (node->attr.sa_vattr.va_type != VDIR) {
378da6c28aaSamw 			rc = smb_lock_range_access(sr, node, param->r_offset,
379*dc20a302Sas200622 			    param->r_count, B_FALSE);
380da6c28aaSamw 			if (rc != NT_STATUS_SUCCESS) {
381da6c28aaSamw 				rc = ERANGE;
382da6c28aaSamw 				break;
383da6c28aaSamw 			}
384da6c28aaSamw 		}
385da6c28aaSamw 
386da6c28aaSamw 		(void) smb_sync_fsattr(sr, sr->user_cr, node);
387da6c28aaSamw 
388da6c28aaSamw 		sr->raw_data.max_bytes = vdb->uio.uio_resid;
389da6c28aaSamw 		top = smb_mbuf_allocate(&vdb->uio);
390da6c28aaSamw 
391da6c28aaSamw 		rc = smb_fsop_read(sr, sr->user_cr, node, &vdb->uio,
392da6c28aaSamw 		    &node->attr);
393da6c28aaSamw 
394da6c28aaSamw 		sr->raw_data.max_bytes -= vdb->uio.uio_resid;
395da6c28aaSamw 		smb_mbuf_trim(top, sr->raw_data.max_bytes);
396da6c28aaSamw 		MBC_ATTACH_MBUF(&sr->raw_data, top);
397da6c28aaSamw 		break;
398da6c28aaSamw 
399da6c28aaSamw 	case STYPE_IPC:
400da6c28aaSamw 		rc = smb_rpc_read(sr, &vdb->uio);
401da6c28aaSamw 		break;
402da6c28aaSamw 
403da6c28aaSamw 	default:
404da6c28aaSamw 		rc = EACCES;
405da6c28aaSamw 		break;
406da6c28aaSamw 	}
407da6c28aaSamw 
408da6c28aaSamw 	param->r_count -= vdb->uio.uio_resid;
409da6c28aaSamw 	kmem_free(vdb, sizeof (struct vardata_block));
410da6c28aaSamw 
411da6c28aaSamw 	if (rc != 0)
412da6c28aaSamw 		return (rc);
413da6c28aaSamw 
414da6c28aaSamw 	if (param->r_mincnt != 0 && param->r_count < param->r_mincnt) {
415da6c28aaSamw 		/*
416da6c28aaSamw 		 * mincnt is only used by read-raw and is typically
417da6c28aaSamw 		 * zero.  If mincnt is greater than zero and the
418da6c28aaSamw 		 * number of bytes read is less than mincnt, tell
419da6c28aaSamw 		 * the client that we read nothing.
420da6c28aaSamw 		 */
421da6c28aaSamw 		param->r_count = 0;
422da6c28aaSamw 	}
423da6c28aaSamw 
424da6c28aaSamw 	param->r_offset += param->r_count;
425da6c28aaSamw 	mutex_enter(&sr->fid_ofile->f_mutex);
426da6c28aaSamw 	ofile->f_seek_pos = param->r_offset;
427da6c28aaSamw 	mutex_exit(&sr->fid_ofile->f_mutex);
428da6c28aaSamw 	return (rc);
429da6c28aaSamw }
430da6c28aaSamw 
431da6c28aaSamw /*
432da6c28aaSamw  * The Read Block Multiplexed protocol is used to maximize performance
433da6c28aaSamw  * when reading a large block of data from server to client while still
434da6c28aaSamw  * allowing other operations to take place between the client and server
435da6c28aaSamw  * in parallel.
436da6c28aaSamw  *
437da6c28aaSamw  * The mpx sub protocol is not supported because we support only
438da6c28aaSamw  * connection oriented transports and NT supports SMB_COM_READ_MPX
439da6c28aaSamw  * only over connectionless transports.
440da6c28aaSamw  */
441da6c28aaSamw /*ARGSUSED*/
442da6c28aaSamw int
443da6c28aaSamw smb_com_read_mpx(struct smb_request *sr)
444da6c28aaSamw {
445da6c28aaSamw 	return (SDRC_UNIMPLEMENTED);
446da6c28aaSamw }
447da6c28aaSamw 
448da6c28aaSamw /*ARGSUSED*/
449da6c28aaSamw int
450da6c28aaSamw smb_com_read_mpx_secondary(struct smb_request *sr)
451da6c28aaSamw {
452da6c28aaSamw 	return (SDRC_UNIMPLEMENTED);
453da6c28aaSamw }
454