xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_read.c (revision 2c2961f8403049d948b9f3e6c35d6488b6b7e1aa)
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*2c2961f8Sjose borrego  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
23da6c28aaSamw  * Use is subject to license terms.
24da6c28aaSamw  */
25da6c28aaSamw 
26da6c28aaSamw #include <smbsrv/smb_incl.h>
27da6c28aaSamw #include <smbsrv/smb_fsops.h>
28da6c28aaSamw 
29da6c28aaSamw 
30*2c2961f8Sjose borrego /*
31*2c2961f8Sjose borrego  * The maximum number of bytes to return from SMB Core
32*2c2961f8Sjose borrego  * SmbRead or SmbLockAndRead.
33*2c2961f8Sjose borrego  */
34*2c2961f8Sjose borrego #define	SMB_CORE_READ_MAX	4432
35da6c28aaSamw 
36*2c2961f8Sjose borrego /*
37*2c2961f8Sjose borrego  * The limit in bytes for SmbReadX.
38*2c2961f8Sjose borrego  */
39*2c2961f8Sjose borrego #define	SMB_READX_MAX		0x10000
40*2c2961f8Sjose borrego 
41*2c2961f8Sjose borrego int smb_common_read(smb_request_t *, smb_rw_param_t *);
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  */
587b59d02dSjb150015 smb_sdrc_t
59faa1795aSjb150015 smb_pre_read(smb_request_t *sr)
60da6c28aaSamw {
61faa1795aSjb150015 	smb_rw_param_t *param;
62da6c28aaSamw 	uint32_t off_low;
63*2c2961f8Sjose borrego 	uint16_t count;
64da6c28aaSamw 	uint16_t remcnt;
65da6c28aaSamw 	int rc;
66da6c28aaSamw 
67faa1795aSjb150015 	param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
68faa1795aSjb150015 	sr->arg.rw = param;
69da6c28aaSamw 
70faa1795aSjb150015 	rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid,
71*2c2961f8Sjose borrego 	    &count, &off_low, &remcnt);
72faa1795aSjb150015 
73faa1795aSjb150015 	param->rw_offset = (uint64_t)off_low;
74*2c2961f8Sjose borrego 	param->rw_count = (uint32_t)count;
75faa1795aSjb150015 	param->rw_mincnt = 0;
76faa1795aSjb150015 
77faa1795aSjb150015 	DTRACE_SMB_2(op__Read__start, smb_request_t *, sr,
78faa1795aSjb150015 	    smb_rw_param_t *, param);
79faa1795aSjb150015 
80faa1795aSjb150015 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
81faa1795aSjb150015 }
82faa1795aSjb150015 
83faa1795aSjb150015 void
84faa1795aSjb150015 smb_post_read(smb_request_t *sr)
85faa1795aSjb150015 {
86faa1795aSjb150015 	DTRACE_SMB_2(op__Read__done, smb_request_t *, sr,
87faa1795aSjb150015 	    smb_rw_param_t *, sr->arg.rw);
88faa1795aSjb150015 
89faa1795aSjb150015 	kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
90faa1795aSjb150015 }
91faa1795aSjb150015 
92faa1795aSjb150015 smb_sdrc_t
93faa1795aSjb150015 smb_com_read(smb_request_t *sr)
94faa1795aSjb150015 {
95faa1795aSjb150015 	smb_rw_param_t *param = sr->arg.rw;
96*2c2961f8Sjose borrego 	uint16_t count;
97faa1795aSjb150015 	int rc;
98da6c28aaSamw 
99*2c2961f8Sjose borrego 	smbsr_lookup_file(sr);
100da6c28aaSamw 	if (sr->fid_ofile == NULL) {
101dc20a302Sas200622 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
102faa1795aSjb150015 		return (SDRC_ERROR);
103da6c28aaSamw 	}
104da6c28aaSamw 
105b89a8333Snatalie li - Sun Microsystems - Irvine United States 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
106b89a8333Snatalie li - Sun Microsystems - Irvine United States 
107*2c2961f8Sjose borrego 	if (param->rw_count > SMB_CORE_READ_MAX)
108*2c2961f8Sjose borrego 		param->rw_count = SMB_CORE_READ_MAX;
109*2c2961f8Sjose borrego 
110faa1795aSjb150015 	if ((rc = smb_common_read(sr, param)) != 0) {
111dc20a302Sas200622 		smbsr_errno(sr, rc);
112faa1795aSjb150015 		return (SDRC_ERROR);
113da6c28aaSamw 	}
114da6c28aaSamw 
115*2c2961f8Sjose borrego 	count = (uint16_t)param->rw_count;
1167b59d02dSjb150015 	rc = smbsr_encode_result(sr, 5, VAR_BCC, "bw8.wbwC",
117*2c2961f8Sjose borrego 	    5, count, VAR_BCC, 0x01, count, &sr->raw_data);
118da6c28aaSamw 
119faa1795aSjb150015 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
120da6c28aaSamw }
121da6c28aaSamw 
122da6c28aaSamw /*
123da6c28aaSamw  * Lock and read bytes from a file (SMB Core Plus).  The SmbLockAndRead/
124da6c28aaSamw  * SmbLockAndWrite sub-dialect is only valid on disk files: reject any
125da6c28aaSamw  * attempt to use it on non-disk shares.
126da6c28aaSamw  *
127da6c28aaSamw  * The requested count specifies the number of bytes desired.  Offset
128da6c28aaSamw  * specifies the offset in the file of the first byte to be locked then
129da6c28aaSamw  * read. Note that offset is limited to 32 bits, so this client request
130da6c28aaSamw  * is inappropriate for files with 64 bit offsets.
131da6c28aaSamw  *
132da6c28aaSamw  * As with SMB_LOCK_BYTE_RANGE request, if the lock cannot be granted
133da6c28aaSamw  * immediately an error should be returned to the client.  If an error
134da6c28aaSamw  * occurs on the lock, the bytes should not be read.
135da6c28aaSamw  *
136da6c28aaSamw  * On return, count is the number of bytes actually being returned, which
137da6c28aaSamw  * may be less than the count requested only if a read specifies bytes
138da6c28aaSamw  * beyond the current file size.  In this case only the bytes that exist
139da6c28aaSamw  * are returned.  A read completely beyond the end of file results in a
140da6c28aaSamw  * response of length zero.  This is the only circumstance when a zero
141da6c28aaSamw  * length response is generated.  A count returned which is less than the
142da6c28aaSamw  * count requested is the end of file indicator.
143da6c28aaSamw  */
1447b59d02dSjb150015 smb_sdrc_t
145faa1795aSjb150015 smb_pre_lock_and_read(smb_request_t *sr)
146da6c28aaSamw {
147faa1795aSjb150015 	smb_rw_param_t *param;
148da6c28aaSamw 	uint32_t off_low;
149*2c2961f8Sjose borrego 	uint16_t count;
150*2c2961f8Sjose borrego 	uint16_t remcnt;
151faa1795aSjb150015 	int rc;
152faa1795aSjb150015 
153faa1795aSjb150015 	param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
154faa1795aSjb150015 	sr->arg.rw = param;
155faa1795aSjb150015 
156faa1795aSjb150015 	rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid,
157*2c2961f8Sjose borrego 	    &count, &off_low, &remcnt);
158faa1795aSjb150015 
159faa1795aSjb150015 	param->rw_offset = (uint64_t)off_low;
160*2c2961f8Sjose borrego 	param->rw_count = (uint32_t)count;
161faa1795aSjb150015 	param->rw_mincnt = 0;
162faa1795aSjb150015 
163faa1795aSjb150015 	DTRACE_SMB_2(op__LockAndRead__start, smb_request_t *, sr,
164faa1795aSjb150015 	    smb_rw_param_t *, param);
165faa1795aSjb150015 
166faa1795aSjb150015 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
167faa1795aSjb150015 }
168faa1795aSjb150015 
169faa1795aSjb150015 void
170faa1795aSjb150015 smb_post_lock_and_read(smb_request_t *sr)
171faa1795aSjb150015 {
172faa1795aSjb150015 	DTRACE_SMB_2(op__LockAndRead__done, smb_request_t *, sr,
173faa1795aSjb150015 	    smb_rw_param_t *, sr->arg.rw);
174faa1795aSjb150015 
175faa1795aSjb150015 	kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
176faa1795aSjb150015 }
177faa1795aSjb150015 
178faa1795aSjb150015 smb_sdrc_t
179faa1795aSjb150015 smb_com_lock_and_read(smb_request_t *sr)
180faa1795aSjb150015 {
181faa1795aSjb150015 	smb_rw_param_t *param = sr->arg.rw;
182faa1795aSjb150015 	DWORD status;
183*2c2961f8Sjose borrego 	uint16_t count;
184da6c28aaSamw 	int rc;
185da6c28aaSamw 
186da6c28aaSamw 	if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) {
187dc20a302Sas200622 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERRnoaccess);
188faa1795aSjb150015 		return (SDRC_ERROR);
189da6c28aaSamw 	}
190da6c28aaSamw 
191*2c2961f8Sjose borrego 	smbsr_lookup_file(sr);
192da6c28aaSamw 	if (sr->fid_ofile == NULL) {
193dc20a302Sas200622 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
194faa1795aSjb150015 		return (SDRC_ERROR);
195da6c28aaSamw 	}
196da6c28aaSamw 
197b89a8333Snatalie li - Sun Microsystems - Irvine United States 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
198b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1996537f381Sas200622 	status = smb_lock_range(sr, param->rw_offset, (uint64_t)param->rw_count,
200*2c2961f8Sjose borrego 	    0, SMB_LOCK_TYPE_READWRITE);
201*2c2961f8Sjose borrego 
202faa1795aSjb150015 	if (status != NT_STATUS_SUCCESS) {
203faa1795aSjb150015 		smb_lock_range_error(sr, status);
204faa1795aSjb150015 		return (SDRC_ERROR);
205da6c28aaSamw 	}
206da6c28aaSamw 
207*2c2961f8Sjose borrego 	if (param->rw_count > SMB_CORE_READ_MAX)
208*2c2961f8Sjose borrego 		param->rw_count = SMB_CORE_READ_MAX;
209*2c2961f8Sjose borrego 
210faa1795aSjb150015 	if ((rc = smb_common_read(sr, param)) != 0) {
211dc20a302Sas200622 		smbsr_errno(sr, rc);
212faa1795aSjb150015 		return (SDRC_ERROR);
213da6c28aaSamw 	}
214da6c28aaSamw 
215*2c2961f8Sjose borrego 	count = (uint16_t)param->rw_count;
2167b59d02dSjb150015 	rc = smbsr_encode_result(sr, 5, VAR_BCC, "bw8.wbwC",
217*2c2961f8Sjose borrego 	    5, count, VAR_BCC, 0x1, count, &sr->raw_data);
218da6c28aaSamw 
219faa1795aSjb150015 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
220da6c28aaSamw }
221da6c28aaSamw 
222da6c28aaSamw /*
223da6c28aaSamw  * The SMB_COM_READ_RAW protocol is a negotiated option introduced in
224da6c28aaSamw  * SMB Core Plus to maximize performance when reading a large block
225da6c28aaSamw  * of data from a server.  This request was extended in LM 0.12 to
226da6c28aaSamw  * support 64-bit offsets; the server can indicate support by setting
227da6c28aaSamw  * CAP_LARGE_FILES in the negotiated capabilities.
228da6c28aaSamw  *
229da6c28aaSamw  * The client must guarantee that there is (and will be) no other request
230da6c28aaSamw  * to the server for the duration of the SMB_COM_READ_RAW, since the
231da6c28aaSamw  * server response has no header or trailer. To help ensure that there
232da6c28aaSamw  * are no interruptions, we block all I/O for the session during read raw.
233da6c28aaSamw  *
234da6c28aaSamw  * If this is the first SMB request received since we sent an oplock break
235da6c28aaSamw  * to this client, we don't know if it's safe to send the raw data because
236da6c28aaSamw  * the requests may have crossed on the wire and the client may have
237da6c28aaSamw  * interpreted the oplock break as part of the raw data. To avoid problems,
238da6c28aaSamw  * we send a zero length session packet, which will force the client to
239da6c28aaSamw  * retry the read.
240da6c28aaSamw  *
241*2c2961f8Sjose borrego  * Do not return errors from SmbReadRaw.
242da6c28aaSamw  * Read errors are handled by sending a zero length response.
243da6c28aaSamw  */
2447b59d02dSjb150015 smb_sdrc_t
245faa1795aSjb150015 smb_pre_read_raw(smb_request_t *sr)
246da6c28aaSamw {
247faa1795aSjb150015 	smb_rw_param_t *param;
248da6c28aaSamw 	uint32_t off_low;
249da6c28aaSamw 	uint32_t off_high;
250da6c28aaSamw 	uint32_t timeout;
251*2c2961f8Sjose borrego 	uint16_t count;
252da6c28aaSamw 	int rc;
253da6c28aaSamw 
254faa1795aSjb150015 	param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
255faa1795aSjb150015 	sr->arg.rw = param;
256faa1795aSjb150015 
257da6c28aaSamw 	if (sr->smb_wct == 8) {
258da6c28aaSamw 		rc = smbsr_decode_vwv(sr, "wlwwl2.", &sr->smb_fid,
259*2c2961f8Sjose borrego 		    &off_low, &count, &param->rw_mincnt, &timeout);
260*2c2961f8Sjose borrego 		if (rc == 0) {
261faa1795aSjb150015 			param->rw_offset = (uint64_t)off_low;
262*2c2961f8Sjose borrego 			param->rw_count = (uint32_t)count;
263*2c2961f8Sjose borrego 		}
264da6c28aaSamw 	} else {
265da6c28aaSamw 		rc = smbsr_decode_vwv(sr, "wlwwl2.l", &sr->smb_fid,
266*2c2961f8Sjose borrego 		    &off_low, &count, &param->rw_mincnt, &timeout, &off_high);
267*2c2961f8Sjose borrego 		if (rc == 0) {
268faa1795aSjb150015 			param->rw_offset = ((uint64_t)off_high << 32) | off_low;
269*2c2961f8Sjose borrego 			param->rw_count = (uint32_t)count;
270*2c2961f8Sjose borrego 		}
271da6c28aaSamw 	}
272da6c28aaSamw 
273faa1795aSjb150015 	DTRACE_SMB_2(op__ReadRaw__start, smb_request_t *, sr,
274faa1795aSjb150015 	    smb_rw_param_t *, param);
275da6c28aaSamw 
276*2c2961f8Sjose borrego 	return (SDRC_SUCCESS);
277faa1795aSjb150015 }
278faa1795aSjb150015 
279faa1795aSjb150015 void
280faa1795aSjb150015 smb_post_read_raw(smb_request_t *sr)
281faa1795aSjb150015 {
282*2c2961f8Sjose borrego 	mbuf_chain_t	*mbc;
283*2c2961f8Sjose borrego 
284*2c2961f8Sjose borrego 	if (sr->session->s_state == SMB_SESSION_STATE_READ_RAW_ACTIVE) {
285*2c2961f8Sjose borrego 		sr->session->s_state = SMB_SESSION_STATE_NEGOTIATED;
286*2c2961f8Sjose borrego 
287*2c2961f8Sjose borrego 		while ((mbc = list_head(&sr->session->s_oplock_brkreqs)) !=
288*2c2961f8Sjose borrego 		    NULL) {
289*2c2961f8Sjose borrego 			SMB_MBC_VALID(mbc);
290*2c2961f8Sjose borrego 			list_remove(&sr->session->s_oplock_brkreqs, mbc);
291*2c2961f8Sjose borrego 			(void) smb_session_send(sr->session, 0, mbc);
292*2c2961f8Sjose borrego 			smb_mbc_free(mbc);
293*2c2961f8Sjose borrego 		}
294*2c2961f8Sjose borrego 	}
295*2c2961f8Sjose borrego 
296faa1795aSjb150015 	DTRACE_SMB_2(op__ReadRaw__done, smb_request_t *, sr,
297faa1795aSjb150015 	    smb_rw_param_t *, sr->arg.rw);
298faa1795aSjb150015 
299faa1795aSjb150015 	kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
300faa1795aSjb150015 }
301faa1795aSjb150015 
302faa1795aSjb150015 smb_sdrc_t
303faa1795aSjb150015 smb_com_read_raw(smb_request_t *sr)
304faa1795aSjb150015 {
305faa1795aSjb150015 	smb_rw_param_t *param = sr->arg.rw;
306faa1795aSjb150015 
307faa1795aSjb150015 	switch (sr->session->s_state) {
308faa1795aSjb150015 	case SMB_SESSION_STATE_NEGOTIATED:
309*2c2961f8Sjose borrego 		sr->session->s_state = SMB_SESSION_STATE_READ_RAW_ACTIVE;
310faa1795aSjb150015 		break;
311faa1795aSjb150015 
312faa1795aSjb150015 	case SMB_SESSION_STATE_OPLOCK_BREAKING:
313faa1795aSjb150015 		(void) smb_session_send(sr->session, 0, NULL);
314faa1795aSjb150015 		return (SDRC_NO_REPLY);
315faa1795aSjb150015 
316faa1795aSjb150015 	case SMB_SESSION_STATE_TERMINATED:
317faa1795aSjb150015 	case SMB_SESSION_STATE_DISCONNECTED:
318faa1795aSjb150015 		return (SDRC_NO_REPLY);
319faa1795aSjb150015 
320*2c2961f8Sjose borrego 	case SMB_SESSION_STATE_READ_RAW_ACTIVE:
321*2c2961f8Sjose borrego 		sr->session->s_state = SMB_SESSION_STATE_NEGOTIATED;
322*2c2961f8Sjose borrego 		return (SDRC_DROP_VC);
323*2c2961f8Sjose borrego 
324faa1795aSjb150015 	case SMB_SESSION_STATE_WRITE_RAW_ACTIVE:
325faa1795aSjb150015 	case SMB_SESSION_STATE_CONNECTED:
326faa1795aSjb150015 	case SMB_SESSION_STATE_ESTABLISHED:
327faa1795aSjb150015 	default:
328faa1795aSjb150015 		return (SDRC_DROP_VC);
329faa1795aSjb150015 	}
330faa1795aSjb150015 
331*2c2961f8Sjose borrego 	smbsr_lookup_file(sr);
332da6c28aaSamw 	if (sr->fid_ofile == NULL) {
333*2c2961f8Sjose borrego 		(void) smb_session_send(sr->session, 0, NULL);
334*2c2961f8Sjose borrego 		return (SDRC_NO_REPLY);
335da6c28aaSamw 	}
336da6c28aaSamw 
337b89a8333Snatalie li - Sun Microsystems - Irvine United States 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
338b89a8333Snatalie li - Sun Microsystems - Irvine United States 
339*2c2961f8Sjose borrego 	if (param->rw_mincnt > param->rw_count)
340*2c2961f8Sjose borrego 		param->rw_mincnt = 0;
341faa1795aSjb150015 
342*2c2961f8Sjose borrego 	if (smb_common_read(sr, param) != 0) {
343da6c28aaSamw 		(void) smb_session_send(sr->session, 0, NULL);
344da6c28aaSamw 		m_freem(sr->raw_data.chain);
345*2c2961f8Sjose borrego 		sr->raw_data.chain = NULL;
346da6c28aaSamw 	} else {
347da6c28aaSamw 		(void) smb_session_send(sr->session, 0, &sr->raw_data);
348da6c28aaSamw 	}
349faa1795aSjb150015 
350da6c28aaSamw 	return (SDRC_NO_REPLY);
351da6c28aaSamw }
352da6c28aaSamw 
353da6c28aaSamw /*
354da6c28aaSamw  * Read bytes from a file (SMB Core).  This request was extended in
355da6c28aaSamw  * LM 0.12 to support 64-bit offsets, indicated by sending a wct of
356da6c28aaSamw  * 12 and including additional offset information.
357*2c2961f8Sjose borrego  *
358*2c2961f8Sjose borrego  * MS-SMB 3.3.5.7 update to LM 0.12 4.2.4:
359*2c2961f8Sjose borrego  * If wct is 12 and CAP_LARGE_READX is set, the count may be larger
360*2c2961f8Sjose borrego  * than the negotiated buffer size.  If maxcnt_high is 0xFF, it must
361*2c2961f8Sjose borrego  * be ignored.  Otherwise, maxcnt_high represents the upper 16 bits
362*2c2961f8Sjose borrego  * of rw_count.
363da6c28aaSamw  */
3647b59d02dSjb150015 smb_sdrc_t
365faa1795aSjb150015 smb_pre_read_andx(smb_request_t *sr)
366da6c28aaSamw {
367faa1795aSjb150015 	smb_rw_param_t *param;
368da6c28aaSamw 	uint32_t off_low;
369da6c28aaSamw 	uint32_t off_high;
370*2c2961f8Sjose borrego 	uint32_t maxcnt_high;
371*2c2961f8Sjose borrego 	uint16_t maxcnt_low;
372*2c2961f8Sjose borrego 	uint16_t mincnt;
373da6c28aaSamw 	uint16_t remcnt;
374da6c28aaSamw 	int rc;
375da6c28aaSamw 
376faa1795aSjb150015 	param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
377faa1795aSjb150015 	sr->arg.rw = param;
378faa1795aSjb150015 
379da6c28aaSamw 	if (sr->smb_wct == 12) {
380*2c2961f8Sjose borrego 		rc = smbsr_decode_vwv(sr, "b3.wlwwlwl", &param->rw_andx,
381*2c2961f8Sjose borrego 		    &sr->smb_fid, &off_low, &maxcnt_low, &mincnt, &maxcnt_high,
382*2c2961f8Sjose borrego 		    &remcnt, &off_high);
383da6c28aaSamw 
384*2c2961f8Sjose borrego 		param->rw_offset = ((uint64_t)off_high << 32) |
385*2c2961f8Sjose borrego 		    (uint64_t)off_low;
386*2c2961f8Sjose borrego 
387*2c2961f8Sjose borrego 		param->rw_count = (uint32_t)maxcnt_low;
388*2c2961f8Sjose borrego 		if (maxcnt_high < 0xFF)
389*2c2961f8Sjose borrego 			param->rw_count |= maxcnt_high << 16;
390da6c28aaSamw 	} else {
391*2c2961f8Sjose borrego 		rc = smbsr_decode_vwv(sr, "b3.wlwwlw", &param->rw_andx,
392*2c2961f8Sjose borrego 		    &sr->smb_fid, &off_low, &maxcnt_low, &mincnt, &maxcnt_high,
393*2c2961f8Sjose borrego 		    &remcnt);
394da6c28aaSamw 
395faa1795aSjb150015 		param->rw_offset = (uint64_t)off_low;
396*2c2961f8Sjose borrego 		param->rw_count = (uint32_t)maxcnt_low;
397da6c28aaSamw 	}
398da6c28aaSamw 
399faa1795aSjb150015 	param->rw_mincnt = 0;
400da6c28aaSamw 
401faa1795aSjb150015 	DTRACE_SMB_2(op__ReadX__start, smb_request_t *, sr,
402faa1795aSjb150015 	    smb_rw_param_t *, param);
403faa1795aSjb150015 
404faa1795aSjb150015 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
405faa1795aSjb150015 }
406faa1795aSjb150015 
407faa1795aSjb150015 void
408faa1795aSjb150015 smb_post_read_andx(smb_request_t *sr)
409faa1795aSjb150015 {
410faa1795aSjb150015 	DTRACE_SMB_2(op__ReadX__done, smb_request_t *, sr,
411faa1795aSjb150015 	    smb_rw_param_t *, sr->arg.rw);
412faa1795aSjb150015 
413faa1795aSjb150015 	kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
414faa1795aSjb150015 }
415faa1795aSjb150015 
416faa1795aSjb150015 smb_sdrc_t
417faa1795aSjb150015 smb_com_read_andx(smb_request_t *sr)
418faa1795aSjb150015 {
419faa1795aSjb150015 	smb_rw_param_t *param = sr->arg.rw;
420*2c2961f8Sjose borrego 	uint16_t datalen_high;
421*2c2961f8Sjose borrego 	uint16_t datalen_low;
422*2c2961f8Sjose borrego 	uint16_t data_offset;
423faa1795aSjb150015 	uint16_t offset2;
424faa1795aSjb150015 	int rc;
425da6c28aaSamw 
426*2c2961f8Sjose borrego 	smbsr_lookup_file(sr);
427da6c28aaSamw 	if (sr->fid_ofile == NULL) {
428dc20a302Sas200622 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
429faa1795aSjb150015 		return (SDRC_ERROR);
430da6c28aaSamw 	}
431da6c28aaSamw 
432b89a8333Snatalie li - Sun Microsystems - Irvine United States 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
433b89a8333Snatalie li - Sun Microsystems - Irvine United States 
434*2c2961f8Sjose borrego 	if (param->rw_count >= SMB_READX_MAX)
435*2c2961f8Sjose borrego 		param->rw_count = 0;
436*2c2961f8Sjose borrego 
437faa1795aSjb150015 	if ((rc = smb_common_read(sr, param)) != 0) {
438dc20a302Sas200622 		smbsr_errno(sr, rc);
439faa1795aSjb150015 		return (SDRC_ERROR);
440da6c28aaSamw 	}
441da6c28aaSamw 
442*2c2961f8Sjose borrego 	datalen_low = param->rw_count & 0xFFFF;
443*2c2961f8Sjose borrego 	datalen_high = (param->rw_count >> 16) & 0xFF;
444da6c28aaSamw 
445da6c28aaSamw 	/*
446*2c2961f8Sjose borrego 	 * If this is a secondary command, the data offset
447*2c2961f8Sjose borrego 	 * includes the previous wct + sizeof(wct).
448da6c28aaSamw 	 */
449*2c2961f8Sjose borrego 	data_offset = (sr->andx_prev_wct == 0) ? 0 : sr->andx_prev_wct + 1;
450*2c2961f8Sjose borrego 
451da6c28aaSamw 	if (STYPE_ISIPC(sr->tid_tree->t_res_type)) {
452*2c2961f8Sjose borrego 		data_offset += 60;
453*2c2961f8Sjose borrego 		offset2 = (param->rw_andx == 0xFF) ? 0 : param->rw_count + 60;
454*2c2961f8Sjose borrego 
455*2c2961f8Sjose borrego 		rc = smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.www8.wbC",
456da6c28aaSamw 		    12,			/* wct */
457*2c2961f8Sjose borrego 		    param->rw_andx,	/* secondary andx command */
458*2c2961f8Sjose borrego 		    offset2,		/* offset to next command */
459*2c2961f8Sjose borrego 		    0,			/* set to 0 for named pipes */
460*2c2961f8Sjose borrego 		    datalen_low,	/* data byte count */
461*2c2961f8Sjose borrego 		    data_offset,	/* offset from start to data */
462*2c2961f8Sjose borrego 		    datalen_high,	/* data byte count */
463da6c28aaSamw 		    VAR_BCC,		/* BCC marker */
464*2c2961f8Sjose borrego 		    0x00,		/* padding */
465da6c28aaSamw 		    &sr->raw_data);
466da6c28aaSamw 	} else {
467*2c2961f8Sjose borrego 		data_offset += 59;
468*2c2961f8Sjose borrego 		offset2 = (param->rw_andx == 0xFF) ? 0 : param->rw_count + 59;
469*2c2961f8Sjose borrego 
470*2c2961f8Sjose borrego 		rc = smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.www8.wC",
471da6c28aaSamw 		    12,			/* wct */
472*2c2961f8Sjose borrego 		    param->rw_andx,	/* secondary andx command */
473*2c2961f8Sjose borrego 		    offset2,		/* offset to next command */
474*2c2961f8Sjose borrego 		    -1,			/* must be -1 for regular files */
475*2c2961f8Sjose borrego 		    datalen_low,	/* data byte count */
476*2c2961f8Sjose borrego 		    data_offset,	/* offset from start to data */
477*2c2961f8Sjose borrego 		    datalen_high,	/* data byte count */
478da6c28aaSamw 		    VAR_BCC,		/* BCC marker */
479da6c28aaSamw 		    &sr->raw_data);
480da6c28aaSamw 	}
481da6c28aaSamw 
482faa1795aSjb150015 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
483da6c28aaSamw }
484da6c28aaSamw 
485da6c28aaSamw /*
486da6c28aaSamw  * Common function for reading files or IPC/MSRPC named pipes.  All
487da6c28aaSamw  * protocol read functions should lookup the fid before calling this
488da6c28aaSamw  * function.  We can't move the fid lookup here because lock-and-read
489da6c28aaSamw  * requires the fid to do locking before attempting the read.
490da6c28aaSamw  *
491da6c28aaSamw  * Returns errno values.
492da6c28aaSamw  */
493da6c28aaSamw int
494faa1795aSjb150015 smb_common_read(smb_request_t *sr, smb_rw_param_t *param)
495da6c28aaSamw {
496da6c28aaSamw 	smb_ofile_t *ofile = sr->fid_ofile;
497da6c28aaSamw 	smb_node_t *node;
498faa1795aSjb150015 	smb_vdb_t *vdb = &param->rw_vdb;
499da6c28aaSamw 	struct mbuf *top;
500da6c28aaSamw 	int rc;
501da6c28aaSamw 
502*2c2961f8Sjose borrego 	vdb->vdb_tag = 0;
503*2c2961f8Sjose borrego 	vdb->vdb_uio.uio_iov = &vdb->vdb_iovec[0];
504*2c2961f8Sjose borrego 	vdb->vdb_uio.uio_iovcnt = MAX_IOVEC;
505*2c2961f8Sjose borrego 	vdb->vdb_uio.uio_resid = param->rw_count;
506*2c2961f8Sjose borrego 	vdb->vdb_uio.uio_loffset = (offset_t)param->rw_offset;
507*2c2961f8Sjose borrego 	vdb->vdb_uio.uio_segflg = UIO_SYSSPACE;
508da6c28aaSamw 
509da6c28aaSamw 	switch (sr->tid_tree->t_res_type & STYPE_MASK) {
510da6c28aaSamw 	case STYPE_DISKTREE:
511da6c28aaSamw 		node = ofile->f_node;
512da6c28aaSamw 
513da6c28aaSamw 		if (node->attr.sa_vattr.va_type != VDIR) {
514faa1795aSjb150015 			rc = smb_lock_range_access(sr, node, param->rw_offset,
515faa1795aSjb150015 			    param->rw_count, B_FALSE);
516da6c28aaSamw 			if (rc != NT_STATUS_SUCCESS) {
517da6c28aaSamw 				rc = ERANGE;
518da6c28aaSamw 				break;
519da6c28aaSamw 			}
520da6c28aaSamw 		}
521da6c28aaSamw 
522*2c2961f8Sjose borrego 		if ((ofile->f_flags & SMB_OFLAGS_EXECONLY) &&
523*2c2961f8Sjose borrego 		    !(sr->smb_flg2 & SMB_FLAGS2_PAGING_IO)) {
524*2c2961f8Sjose borrego 			/*
525*2c2961f8Sjose borrego 			 * SMB_FLAGS2_PAGING_IO: permit execute-only reads.
526*2c2961f8Sjose borrego 			 *
527*2c2961f8Sjose borrego 			 * Reject request if the file has been opened
528*2c2961f8Sjose borrego 			 * execute-only and SMB_FLAGS2_PAGING_IO is not set.
529*2c2961f8Sjose borrego 			 */
530*2c2961f8Sjose borrego 			rc = EACCES;
531*2c2961f8Sjose borrego 			break;
532*2c2961f8Sjose borrego 		}
533*2c2961f8Sjose borrego 
534da6c28aaSamw 		(void) smb_sync_fsattr(sr, sr->user_cr, node);
535da6c28aaSamw 
536*2c2961f8Sjose borrego 		sr->raw_data.max_bytes = vdb->vdb_uio.uio_resid;
537*2c2961f8Sjose borrego 		top = smb_mbuf_allocate(&vdb->vdb_uio);
538da6c28aaSamw 
539*2c2961f8Sjose borrego 		rc = smb_fsop_read(sr, sr->user_cr, node, &vdb->vdb_uio,
540da6c28aaSamw 		    &node->attr);
541da6c28aaSamw 
542*2c2961f8Sjose borrego 		sr->raw_data.max_bytes -= vdb->vdb_uio.uio_resid;
543da6c28aaSamw 		smb_mbuf_trim(top, sr->raw_data.max_bytes);
544da6c28aaSamw 		MBC_ATTACH_MBUF(&sr->raw_data, top);
545da6c28aaSamw 		break;
546da6c28aaSamw 
547da6c28aaSamw 	case STYPE_IPC:
548*2c2961f8Sjose borrego 		rc = smb_opipe_read(sr, &vdb->vdb_uio);
549da6c28aaSamw 		break;
550da6c28aaSamw 
551da6c28aaSamw 	default:
552da6c28aaSamw 		rc = EACCES;
553da6c28aaSamw 		break;
554da6c28aaSamw 	}
555da6c28aaSamw 
556*2c2961f8Sjose borrego 	param->rw_count -= vdb->vdb_uio.uio_resid;
557da6c28aaSamw 
558da6c28aaSamw 	if (rc != 0)
559da6c28aaSamw 		return (rc);
560da6c28aaSamw 
561faa1795aSjb150015 	if (param->rw_mincnt != 0 && param->rw_count < param->rw_mincnt) {
562da6c28aaSamw 		/*
563da6c28aaSamw 		 * mincnt is only used by read-raw and is typically
564da6c28aaSamw 		 * zero.  If mincnt is greater than zero and the
565da6c28aaSamw 		 * number of bytes read is less than mincnt, tell
566da6c28aaSamw 		 * the client that we read nothing.
567da6c28aaSamw 		 */
568faa1795aSjb150015 		param->rw_count = 0;
569da6c28aaSamw 	}
570da6c28aaSamw 
571faa1795aSjb150015 	param->rw_offset += param->rw_count;
572da6c28aaSamw 	mutex_enter(&sr->fid_ofile->f_mutex);
573faa1795aSjb150015 	ofile->f_seek_pos = param->rw_offset;
574da6c28aaSamw 	mutex_exit(&sr->fid_ofile->f_mutex);
575da6c28aaSamw 	return (rc);
576da6c28aaSamw }
577