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 /*
22cb174861Sjoyce mcintosh  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23*68b2bbf2SGordon Ross  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
24da6c28aaSamw  */
25da6c28aaSamw 
26bbf6f00cSJordan Brown #include <smbsrv/smb_kproto.h>
27da6c28aaSamw #include <smbsrv/smb_fsops.h>
28da6c28aaSamw 
292c2961f8Sjose borrego /*
302c2961f8Sjose borrego  * The maximum number of bytes to return from SMB Core
312c2961f8Sjose borrego  * SmbRead or SmbLockAndRead.
322c2961f8Sjose borrego  */
332c2961f8Sjose borrego #define	SMB_CORE_READ_MAX	4432
342c2961f8Sjose borrego 
352c2961f8Sjose borrego /*
362c2961f8Sjose borrego  * The limit in bytes for SmbReadX.
372c2961f8Sjose borrego  */
382c2961f8Sjose borrego #define	SMB_READX_MAX		0x10000
39da6c28aaSamw 
402c2961f8Sjose borrego int smb_common_read(smb_request_t *, smb_rw_param_t *);
41da6c28aaSamw 
42da6c28aaSamw /*
43da6c28aaSamw  * Read bytes from a file or named pipe (SMB Core).
44da6c28aaSamw  *
45da6c28aaSamw  * The requested count specifies the number of bytes desired.  Offset
46da6c28aaSamw  * is limited to 32 bits, so this client request is inappropriate for
47da6c28aaSamw  * files with 64 bit offsets.
48da6c28aaSamw  *
49da6c28aaSamw  * On return, count is the number of bytes actually being returned, which
50da6c28aaSamw  * may be less than the count requested only if a read specifies bytes
51da6c28aaSamw  * beyond the current file size.  In this case only the bytes that exist
52da6c28aaSamw  * are returned.  A read completely beyond the end of file results in a
53da6c28aaSamw  * response of length zero.  This is the only circumstance when a zero
54da6c28aaSamw  * length response is generated.  A count returned which is less than the
55da6c28aaSamw  * count requested is the end of file indicator.
56da6c28aaSamw  */
577b59d02dSjb smb_sdrc_t
58faa1795aSjb smb_pre_read(smb_request_t *sr)
59da6c28aaSamw {
60faa1795aSjb 	smb_rw_param_t *param;
61da6c28aaSamw 	uint32_t off_low;
622c2961f8Sjose borrego 	uint16_t count;
63da6c28aaSamw 	uint16_t remcnt;
64da6c28aaSamw 	int rc;
65da6c28aaSamw 
66faa1795aSjb 	param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
67faa1795aSjb 	sr->arg.rw = param;
68faa1795aSjb 
69da6c28aaSamw 	rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid,
702c2961f8Sjose borrego 	    &count, &off_low, &remcnt);
71faa1795aSjb 
72faa1795aSjb 	param->rw_offset = (uint64_t)off_low;
732c2961f8Sjose borrego 	param->rw_count = (uint32_t)count;
74faa1795aSjb 	param->rw_mincnt = 0;
75faa1795aSjb 
76faa1795aSjb 	DTRACE_SMB_2(op__Read__start, smb_request_t *, sr,
77faa1795aSjb 	    smb_rw_param_t *, param);
78faa1795aSjb 
79faa1795aSjb 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
80faa1795aSjb }
81faa1795aSjb 
82faa1795aSjb void
83faa1795aSjb smb_post_read(smb_request_t *sr)
84faa1795aSjb {
85faa1795aSjb 	DTRACE_SMB_2(op__Read__done, smb_request_t *, sr,
86faa1795aSjb 	    smb_rw_param_t *, sr->arg.rw);
87da6c28aaSamw 
88faa1795aSjb 	kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
89faa1795aSjb }
90faa1795aSjb 
91faa1795aSjb smb_sdrc_t
92faa1795aSjb smb_com_read(smb_request_t *sr)
93faa1795aSjb {
94faa1795aSjb 	smb_rw_param_t *param = sr->arg.rw;
952c2961f8Sjose borrego 	uint16_t count;
96faa1795aSjb 	int rc;
97da6c28aaSamw 
982c2961f8Sjose borrego 	smbsr_lookup_file(sr);
99da6c28aaSamw 	if (sr->fid_ofile == NULL) {
100dc20a302Sas 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
101faa1795aSjb 		return (SDRC_ERROR);
102da6c28aaSamw 	}
103da6c28aaSamw 
104b89a8333Snatalie li - Sun Microsystems - Irvine United States 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
105b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1062c2961f8Sjose borrego 	if (param->rw_count > SMB_CORE_READ_MAX)
1072c2961f8Sjose borrego 		param->rw_count = SMB_CORE_READ_MAX;
1082c2961f8Sjose borrego 
109faa1795aSjb 	if ((rc = smb_common_read(sr, param)) != 0) {
110dc20a302Sas 		smbsr_errno(sr, rc);
111faa1795aSjb 		return (SDRC_ERROR);
112da6c28aaSamw 	}
113da6c28aaSamw 
1142c2961f8Sjose borrego 	count = (uint16_t)param->rw_count;
1157b59d02dSjb 	rc = smbsr_encode_result(sr, 5, VAR_BCC, "bw8.wbwC",
1162c2961f8Sjose borrego 	    5, count, VAR_BCC, 0x01, count, &sr->raw_data);
117da6c28aaSamw 
118faa1795aSjb 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
119da6c28aaSamw }
120da6c28aaSamw 
121da6c28aaSamw /*
122da6c28aaSamw  * Lock and read bytes from a file (SMB Core Plus).  The SmbLockAndRead/
123da6c28aaSamw  * SmbLockAndWrite sub-dialect is only valid on disk files: reject any
124da6c28aaSamw  * attempt to use it on non-disk shares.
125da6c28aaSamw  *
126da6c28aaSamw  * The requested count specifies the number of bytes desired.  Offset
127da6c28aaSamw  * specifies the offset in the file of the first byte to be locked then
128da6c28aaSamw  * read. Note that offset is limited to 32 bits, so this client request
129da6c28aaSamw  * is inappropriate for files with 64 bit offsets.
130da6c28aaSamw  *
131da6c28aaSamw  * As with SMB_LOCK_BYTE_RANGE request, if the lock cannot be granted
132da6c28aaSamw  * immediately an error should be returned to the client.  If an error
133da6c28aaSamw  * occurs on the lock, the bytes should not be read.
134da6c28aaSamw  *
135da6c28aaSamw  * On return, count is the number of bytes actually being returned, which
136da6c28aaSamw  * may be less than the count requested only if a read specifies bytes
137da6c28aaSamw  * beyond the current file size.  In this case only the bytes that exist
138da6c28aaSamw  * are returned.  A read completely beyond the end of file results in a
139da6c28aaSamw  * response of length zero.  This is the only circumstance when a zero
140da6c28aaSamw  * length response is generated.  A count returned which is less than the
141da6c28aaSamw  * count requested is the end of file indicator.
142da6c28aaSamw  */
1437b59d02dSjb smb_sdrc_t
144faa1795aSjb smb_pre_lock_and_read(smb_request_t *sr)
145da6c28aaSamw {
146faa1795aSjb 	smb_rw_param_t *param;
147da6c28aaSamw 	uint32_t off_low;
1482c2961f8Sjose borrego 	uint16_t count;
1492c2961f8Sjose borrego 	uint16_t remcnt;
150da6c28aaSamw 	int rc;
151da6c28aaSamw 
152faa1795aSjb 	param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
153faa1795aSjb 	sr->arg.rw = param;
154da6c28aaSamw 
155da6c28aaSamw 	rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid,
1562c2961f8Sjose borrego 	    &count, &off_low, &remcnt);
157faa1795aSjb 
158faa1795aSjb 	param->rw_offset = (uint64_t)off_low;
1592c2961f8Sjose borrego 	param->rw_count = (uint32_t)count;
160faa1795aSjb 	param->rw_mincnt = 0;
161faa1795aSjb 
162faa1795aSjb 	DTRACE_SMB_2(op__LockAndRead__start, smb_request_t *, sr,
163faa1795aSjb 	    smb_rw_param_t *, param);
164faa1795aSjb 
165faa1795aSjb 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
166faa1795aSjb }
167faa1795aSjb 
168faa1795aSjb void
169faa1795aSjb smb_post_lock_and_read(smb_request_t *sr)
170faa1795aSjb {
171faa1795aSjb 	DTRACE_SMB_2(op__LockAndRead__done, smb_request_t *, sr,
172faa1795aSjb 	    smb_rw_param_t *, sr->arg.rw);
173faa1795aSjb 
174faa1795aSjb 	kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
175faa1795aSjb }
176da6c28aaSamw 
177faa1795aSjb smb_sdrc_t
178faa1795aSjb smb_com_lock_and_read(smb_request_t *sr)
179faa1795aSjb {
180faa1795aSjb 	smb_rw_param_t *param = sr->arg.rw;
181faa1795aSjb 	DWORD status;
1822c2961f8Sjose borrego 	uint16_t count;
183faa1795aSjb 	int rc;
184faa1795aSjb 
185faa1795aSjb 	if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) {
186faa1795aSjb 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERRnoaccess);
187faa1795aSjb 		return (SDRC_ERROR);
188faa1795aSjb 	}
189da6c28aaSamw 
1902c2961f8Sjose borrego 	smbsr_lookup_file(sr);
191da6c28aaSamw 	if (sr->fid_ofile == NULL) {
192dc20a302Sas 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
193faa1795aSjb 		return (SDRC_ERROR);
194da6c28aaSamw 	}
195da6c28aaSamw 
196b89a8333Snatalie li - Sun Microsystems - Irvine United States 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
197b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1986537f381Sas 	status = smb_lock_range(sr, param->rw_offset, (uint64_t)param->rw_count,
1992c2961f8Sjose borrego 	    0, SMB_LOCK_TYPE_READWRITE);
2002c2961f8Sjose borrego 
201faa1795aSjb 	if (status != NT_STATUS_SUCCESS) {
202faa1795aSjb 		smb_lock_range_error(sr, status);
203faa1795aSjb 		return (SDRC_ERROR);
204da6c28aaSamw 	}
205da6c28aaSamw 
2062c2961f8Sjose borrego 	if (param->rw_count > SMB_CORE_READ_MAX)
2072c2961f8Sjose borrego 		param->rw_count = SMB_CORE_READ_MAX;
2082c2961f8Sjose borrego 
209faa1795aSjb 	if ((rc = smb_common_read(sr, param)) != 0) {
210dc20a302Sas 		smbsr_errno(sr, rc);
211faa1795aSjb 		return (SDRC_ERROR);
212da6c28aaSamw 	}
213da6c28aaSamw 
2142c2961f8Sjose borrego 	count = (uint16_t)param->rw_count;
2157b59d02dSjb 	rc = smbsr_encode_result(sr, 5, VAR_BCC, "bw8.wbwC",
2162c2961f8Sjose borrego 	    5, count, VAR_BCC, 0x1, count, &sr->raw_data);
217da6c28aaSamw 
218faa1795aSjb 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
219da6c28aaSamw }
220da6c28aaSamw 
221da6c28aaSamw /*
222da6c28aaSamw  * Read bytes from a file (SMB Core).  This request was extended in
223da6c28aaSamw  * LM 0.12 to support 64-bit offsets, indicated by sending a wct of
224da6c28aaSamw  * 12 and including additional offset information.
2252c2961f8Sjose borrego  *
2262c2961f8Sjose borrego  * MS-SMB 3.3.5.7 update to LM 0.12 4.2.4:
2272c2961f8Sjose borrego  * If wct is 12 and CAP_LARGE_READX is set, the count may be larger
2282c2961f8Sjose borrego  * than the negotiated buffer size.  If maxcnt_high is 0xFF, it must
2292c2961f8Sjose borrego  * be ignored.  Otherwise, maxcnt_high represents the upper 16 bits
2302c2961f8Sjose borrego  * of rw_count.
231da6c28aaSamw  */
2327b59d02dSjb smb_sdrc_t
233faa1795aSjb smb_pre_read_andx(smb_request_t *sr)
234da6c28aaSamw {
235faa1795aSjb 	smb_rw_param_t *param;
236da6c28aaSamw 	uint32_t off_low;
237da6c28aaSamw 	uint32_t off_high;
2382c2961f8Sjose borrego 	uint32_t maxcnt_high;
2392c2961f8Sjose borrego 	uint16_t maxcnt_low;
2402c2961f8Sjose borrego 	uint16_t mincnt;
241da6c28aaSamw 	uint16_t remcnt;
242da6c28aaSamw 	int rc;
243da6c28aaSamw 
244faa1795aSjb 	param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
245faa1795aSjb 	sr->arg.rw = param;
246faa1795aSjb 
247da6c28aaSamw 	if (sr->smb_wct == 12) {
2482c2961f8Sjose borrego 		rc = smbsr_decode_vwv(sr, "b3.wlwwlwl", &param->rw_andx,
2492c2961f8Sjose borrego 		    &sr->smb_fid, &off_low, &maxcnt_low, &mincnt, &maxcnt_high,
2502c2961f8Sjose borrego 		    &remcnt, &off_high);
2512c2961f8Sjose borrego 
2522c2961f8Sjose borrego 		param->rw_offset = ((uint64_t)off_high << 32) |
2532c2961f8Sjose borrego 		    (uint64_t)off_low;
254da6c28aaSamw 
2552c2961f8Sjose borrego 		param->rw_count = (uint32_t)maxcnt_low;
2563a6c5f83SAlan Wright 
2573a6c5f83SAlan Wright 		if ((sr->session->capabilities & CAP_LARGE_READX) &&
2583a6c5f83SAlan Wright 		    (maxcnt_high < 0xFF))
2592c2961f8Sjose borrego 			param->rw_count |= maxcnt_high << 16;
260da6c28aaSamw 	} else {
2612c2961f8Sjose borrego 		rc = smbsr_decode_vwv(sr, "b3.wlwwlw", &param->rw_andx,
2622c2961f8Sjose borrego 		    &sr->smb_fid, &off_low, &maxcnt_low, &mincnt, &maxcnt_high,
2632c2961f8Sjose borrego 		    &remcnt);
264da6c28aaSamw 
265faa1795aSjb 		param->rw_offset = (uint64_t)off_low;
2662c2961f8Sjose borrego 		param->rw_count = (uint32_t)maxcnt_low;
267da6c28aaSamw 	}
268da6c28aaSamw 
269faa1795aSjb 	param->rw_mincnt = 0;
270faa1795aSjb 
271faa1795aSjb 	DTRACE_SMB_2(op__ReadX__start, smb_request_t *, sr,
272faa1795aSjb 	    smb_rw_param_t *, param);
273faa1795aSjb 
274faa1795aSjb 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
275faa1795aSjb }
276da6c28aaSamw 
277faa1795aSjb void
278faa1795aSjb smb_post_read_andx(smb_request_t *sr)
279faa1795aSjb {
280faa1795aSjb 	DTRACE_SMB_2(op__ReadX__done, smb_request_t *, sr,
281faa1795aSjb 	    smb_rw_param_t *, sr->arg.rw);
282faa1795aSjb 
283faa1795aSjb 	kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
284faa1795aSjb }
285faa1795aSjb 
286faa1795aSjb smb_sdrc_t
287faa1795aSjb smb_com_read_andx(smb_request_t *sr)
288faa1795aSjb {
289faa1795aSjb 	smb_rw_param_t *param = sr->arg.rw;
2902c2961f8Sjose borrego 	uint16_t datalen_high;
2912c2961f8Sjose borrego 	uint16_t datalen_low;
2922c2961f8Sjose borrego 	uint16_t data_offset;
293faa1795aSjb 	uint16_t offset2;
294faa1795aSjb 	int rc;
295da6c28aaSamw 
2962c2961f8Sjose borrego 	smbsr_lookup_file(sr);
297da6c28aaSamw 	if (sr->fid_ofile == NULL) {
298dc20a302Sas 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
299faa1795aSjb 		return (SDRC_ERROR);
300da6c28aaSamw 	}
301da6c28aaSamw 
302b89a8333Snatalie li - Sun Microsystems - Irvine United States 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
303b89a8333Snatalie li - Sun Microsystems - Irvine United States 
3042c2961f8Sjose borrego 	if (param->rw_count >= SMB_READX_MAX)
3052c2961f8Sjose borrego 		param->rw_count = 0;
3062c2961f8Sjose borrego 
307faa1795aSjb 	if ((rc = smb_common_read(sr, param)) != 0) {
308dc20a302Sas 		smbsr_errno(sr, rc);
309faa1795aSjb 		return (SDRC_ERROR);
310da6c28aaSamw 	}
311da6c28aaSamw 
3122c2961f8Sjose borrego 	datalen_low = param->rw_count & 0xFFFF;
3132c2961f8Sjose borrego 	datalen_high = (param->rw_count >> 16) & 0xFF;
314da6c28aaSamw 
315da6c28aaSamw 	/*
3162c2961f8Sjose borrego 	 * If this is a secondary command, the data offset
3172c2961f8Sjose borrego 	 * includes the previous wct + sizeof(wct).
318da6c28aaSamw 	 */
3192c2961f8Sjose borrego 	data_offset = (sr->andx_prev_wct == 0) ? 0 : sr->andx_prev_wct + 1;
3202c2961f8Sjose borrego 
321da6c28aaSamw 	if (STYPE_ISIPC(sr->tid_tree->t_res_type)) {
3222c2961f8Sjose borrego 		data_offset += 60;
3232c2961f8Sjose borrego 		offset2 = (param->rw_andx == 0xFF) ? 0 : param->rw_count + 60;
3242c2961f8Sjose borrego 
3252c2961f8Sjose borrego 		rc = smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.www8.wbC",
326da6c28aaSamw 		    12,			/* wct */
3272c2961f8Sjose borrego 		    param->rw_andx,	/* secondary andx command */
3282c2961f8Sjose borrego 		    offset2,		/* offset to next command */
3292c2961f8Sjose borrego 		    0,			/* set to 0 for named pipes */
3302c2961f8Sjose borrego 		    datalen_low,	/* data byte count */
3312c2961f8Sjose borrego 		    data_offset,	/* offset from start to data */
3322c2961f8Sjose borrego 		    datalen_high,	/* data byte count */
333da6c28aaSamw 		    VAR_BCC,		/* BCC marker */
3342c2961f8Sjose borrego 		    0x00,		/* padding */
335da6c28aaSamw 		    &sr->raw_data);
336da6c28aaSamw 	} else {
3372c2961f8Sjose borrego 		data_offset += 59;
3382c2961f8Sjose borrego 		offset2 = (param->rw_andx == 0xFF) ? 0 : param->rw_count + 59;
3392c2961f8Sjose borrego 
3402c2961f8Sjose borrego 		rc = smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.www8.wC",
341da6c28aaSamw 		    12,			/* wct */
3422c2961f8Sjose borrego 		    param->rw_andx,	/* secondary andx command */
3432c2961f8Sjose borrego 		    offset2,		/* offset to next command */
3442c2961f8Sjose borrego 		    -1,			/* must be -1 for regular files */
3452c2961f8Sjose borrego 		    datalen_low,	/* data byte count */
3462c2961f8Sjose borrego 		    data_offset,	/* offset from start to data */
3472c2961f8Sjose borrego 		    datalen_high,	/* data byte count */
348da6c28aaSamw 		    VAR_BCC,		/* BCC marker */
349da6c28aaSamw 		    &sr->raw_data);
350da6c28aaSamw 	}
351da6c28aaSamw 
352faa1795aSjb 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
353da6c28aaSamw }
354da6c28aaSamw 
355da6c28aaSamw /*
356da6c28aaSamw  * Common function for reading files or IPC/MSRPC named pipes.  All
357da6c28aaSamw  * protocol read functions should lookup the fid before calling this
358da6c28aaSamw  * function.  We can't move the fid lookup here because lock-and-read
359da6c28aaSamw  * requires the fid to do locking before attempting the read.
360da6c28aaSamw  *
361cb174861Sjoyce mcintosh  * Reading from a file should break oplocks on the file to LEVEL_II.
362cb174861Sjoyce mcintosh  * A call to smb_oplock_break(SMB_OPLOCK_BREAK_TO_LEVEL_II) is not
363cb174861Sjoyce mcintosh  * required as it is a no-op. If there's anything greater than a
364cb174861Sjoyce mcintosh  * LEVEL_II oplock on the file, the oplock MUST be owned by the ofile
365cb174861Sjoyce mcintosh  * on which the read is occuring and therefore would not be broken.
366cb174861Sjoyce mcintosh  *
367da6c28aaSamw  * Returns errno values.
368da6c28aaSamw  */
369da6c28aaSamw int
370faa1795aSjb smb_common_read(smb_request_t *sr, smb_rw_param_t *param)
371da6c28aaSamw {
372da6c28aaSamw 	smb_ofile_t *ofile = sr->fid_ofile;
373da6c28aaSamw 	smb_node_t *node;
374faa1795aSjb 	smb_vdb_t *vdb = &param->rw_vdb;
375da6c28aaSamw 	struct mbuf *top;
376da6c28aaSamw 	int rc;
377da6c28aaSamw 
3782c2961f8Sjose borrego 	vdb->vdb_tag = 0;
3792c2961f8Sjose borrego 	vdb->vdb_uio.uio_iov = &vdb->vdb_iovec[0];
3802c2961f8Sjose borrego 	vdb->vdb_uio.uio_iovcnt = MAX_IOVEC;
3812c2961f8Sjose borrego 	vdb->vdb_uio.uio_resid = param->rw_count;
3822c2961f8Sjose borrego 	vdb->vdb_uio.uio_loffset = (offset_t)param->rw_offset;
3832c2961f8Sjose borrego 	vdb->vdb_uio.uio_segflg = UIO_SYSSPACE;
384f96bd5c8SAlan Wright 	vdb->vdb_uio.uio_extflg = UIO_COPY_DEFAULT;
385da6c28aaSamw 
386da6c28aaSamw 	switch (sr->tid_tree->t_res_type & STYPE_MASK) {
387da6c28aaSamw 	case STYPE_DISKTREE:
388da6c28aaSamw 		node = ofile->f_node;
389da6c28aaSamw 
390037cac00Sjoyce mcintosh 		if (!smb_node_is_dir(node)) {
391faa1795aSjb 			rc = smb_lock_range_access(sr, node, param->rw_offset,
392faa1795aSjb 			    param->rw_count, B_FALSE);
393da6c28aaSamw 			if (rc != NT_STATUS_SUCCESS) {
394da6c28aaSamw 				rc = ERANGE;
395da6c28aaSamw 				break;
396da6c28aaSamw 			}
397da6c28aaSamw 		}
398da6c28aaSamw 
3992c2961f8Sjose borrego 		if ((ofile->f_flags & SMB_OFLAGS_EXECONLY) &&
4009fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 		    !(sr->smb_flg2 & SMB_FLAGS2_READ_IF_EXECUTE)) {
4012c2961f8Sjose borrego 			/*
4029fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			 * SMB_FLAGS2_READ_IF_EXECUTE: permit execute-only
4039fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			 * reads.
4042c2961f8Sjose borrego 			 *
4052c2961f8Sjose borrego 			 * Reject request if the file has been opened
4069fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			 * execute-only and SMB_FLAGS2_READ_IF_EXECUTE is not
4079fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States 			 * set.
4082c2961f8Sjose borrego 			 */
4092c2961f8Sjose borrego 			rc = EACCES;
4102c2961f8Sjose borrego 			break;
4112c2961f8Sjose borrego 		}
4122c2961f8Sjose borrego 
4132c2961f8Sjose borrego 		sr->raw_data.max_bytes = vdb->vdb_uio.uio_resid;
4142c2961f8Sjose borrego 		top = smb_mbuf_allocate(&vdb->vdb_uio);
415da6c28aaSamw 
416037cac00Sjoyce mcintosh 		rc = smb_fsop_read(sr, sr->user_cr, node, &vdb->vdb_uio);
417da6c28aaSamw 
4182c2961f8Sjose borrego 		sr->raw_data.max_bytes -= vdb->vdb_uio.uio_resid;
419da6c28aaSamw 		smb_mbuf_trim(top, sr->raw_data.max_bytes);
420da6c28aaSamw 		MBC_ATTACH_MBUF(&sr->raw_data, top);
421da6c28aaSamw 		break;
422da6c28aaSamw 
423da6c28aaSamw 	case STYPE_IPC:
424*68b2bbf2SGordon Ross 		sr->raw_data.max_bytes = vdb->vdb_uio.uio_resid;
425*68b2bbf2SGordon Ross 		top = smb_mbuf_allocate(&vdb->vdb_uio);
426*68b2bbf2SGordon Ross 
4272c2961f8Sjose borrego 		rc = smb_opipe_read(sr, &vdb->vdb_uio);
428*68b2bbf2SGordon Ross 
429*68b2bbf2SGordon Ross 		sr->raw_data.max_bytes -= vdb->vdb_uio.uio_resid;
430*68b2bbf2SGordon Ross 		smb_mbuf_trim(top, sr->raw_data.max_bytes);
431*68b2bbf2SGordon Ross 		MBC_ATTACH_MBUF(&sr->raw_data, top);
432da6c28aaSamw 		break;
433da6c28aaSamw 
434da6c28aaSamw 	default:
435da6c28aaSamw 		rc = EACCES;
436da6c28aaSamw 		break;
437da6c28aaSamw 	}
438da6c28aaSamw 
4392c2961f8Sjose borrego 	param->rw_count -= vdb->vdb_uio.uio_resid;
440da6c28aaSamw 
441da6c28aaSamw 	if (rc != 0)
442da6c28aaSamw 		return (rc);
443da6c28aaSamw 
444faa1795aSjb 	if (param->rw_mincnt != 0 && param->rw_count < param->rw_mincnt) {
445da6c28aaSamw 		/*
446da6c28aaSamw 		 * mincnt is only used by read-raw and is typically
447da6c28aaSamw 		 * zero.  If mincnt is greater than zero and the
448da6c28aaSamw 		 * number of bytes read is less than mincnt, tell
449da6c28aaSamw 		 * the client that we read nothing.
450da6c28aaSamw 		 */
451faa1795aSjb 		param->rw_count = 0;
452da6c28aaSamw 	}
453da6c28aaSamw 
454faa1795aSjb 	param->rw_offset += param->rw_count;
455da6c28aaSamw 	mutex_enter(&sr->fid_ofile->f_mutex);
456faa1795aSjb 	ofile->f_seek_pos = param->rw_offset;
457da6c28aaSamw 	mutex_exit(&sr->fid_ofile->f_mutex);
458da6c28aaSamw 	return (rc);
459da6c28aaSamw }
460