xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_read.c (revision b89a8333f5e1f75ec0c269b22524bd2eccb972ba)
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 /*
22dc20a302Sas200622  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23da6c28aaSamw  * Use is subject to license terms.
24da6c28aaSamw  */
25da6c28aaSamw 
26da6c28aaSamw #include <sys/syslog.h>
27da6c28aaSamw #include <smbsrv/smb_incl.h>
28da6c28aaSamw #include <smbsrv/smb_fsops.h>
29da6c28aaSamw 
30da6c28aaSamw 
31faa1795aSjb150015 int smb_common_read(smb_request_t *, smb_rw_param_t *);
32da6c28aaSamw 
33da6c28aaSamw 
34da6c28aaSamw /*
35da6c28aaSamw  * Read bytes from a file or named pipe (SMB Core).
36da6c28aaSamw  *
37da6c28aaSamw  * The requested count specifies the number of bytes desired.  Offset
38da6c28aaSamw  * is limited to 32 bits, so this client request is inappropriate for
39da6c28aaSamw  * files with 64 bit offsets.
40da6c28aaSamw  *
41da6c28aaSamw  * On return, count is the number of bytes actually being returned, which
42da6c28aaSamw  * may be less than the count requested only if a read specifies bytes
43da6c28aaSamw  * beyond the current file size.  In this case only the bytes that exist
44da6c28aaSamw  * are returned.  A read completely beyond the end of file results in a
45da6c28aaSamw  * response of length zero.  This is the only circumstance when a zero
46da6c28aaSamw  * length response is generated.  A count returned which is less than the
47da6c28aaSamw  * count requested is the end of file indicator.
48da6c28aaSamw  */
497b59d02dSjb150015 smb_sdrc_t
50faa1795aSjb150015 smb_pre_read(smb_request_t *sr)
51da6c28aaSamw {
52faa1795aSjb150015 	smb_rw_param_t *param;
53da6c28aaSamw 	uint32_t off_low;
54da6c28aaSamw 	uint16_t remcnt;
55da6c28aaSamw 	int rc;
56da6c28aaSamw 
57faa1795aSjb150015 	param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
58faa1795aSjb150015 	sr->arg.rw = param;
59da6c28aaSamw 
60faa1795aSjb150015 	rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid,
61faa1795aSjb150015 	    &param->rw_count, &off_low, &remcnt);
62faa1795aSjb150015 
63faa1795aSjb150015 	param->rw_offset = (uint64_t)off_low;
64faa1795aSjb150015 	param->rw_mincnt = 0;
65faa1795aSjb150015 
66faa1795aSjb150015 	DTRACE_SMB_2(op__Read__start, smb_request_t *, sr,
67faa1795aSjb150015 	    smb_rw_param_t *, param);
68faa1795aSjb150015 
69faa1795aSjb150015 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
70faa1795aSjb150015 }
71faa1795aSjb150015 
72faa1795aSjb150015 void
73faa1795aSjb150015 smb_post_read(smb_request_t *sr)
74faa1795aSjb150015 {
75faa1795aSjb150015 	DTRACE_SMB_2(op__Read__done, smb_request_t *, sr,
76faa1795aSjb150015 	    smb_rw_param_t *, sr->arg.rw);
77faa1795aSjb150015 
78faa1795aSjb150015 	kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
79faa1795aSjb150015 }
80faa1795aSjb150015 
81faa1795aSjb150015 smb_sdrc_t
82faa1795aSjb150015 smb_com_read(smb_request_t *sr)
83faa1795aSjb150015 {
84faa1795aSjb150015 	smb_rw_param_t *param = sr->arg.rw;
85faa1795aSjb150015 	int rc;
86da6c28aaSamw 
87da6c28aaSamw 	sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
88da6c28aaSamw 	if (sr->fid_ofile == NULL) {
89dc20a302Sas200622 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
90faa1795aSjb150015 		return (SDRC_ERROR);
91da6c28aaSamw 	}
92da6c28aaSamw 
93*b89a8333Snatalie li - Sun Microsystems - Irvine United States 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
94*b89a8333Snatalie li - Sun Microsystems - Irvine United States 
95faa1795aSjb150015 	if ((rc = smb_common_read(sr, param)) != 0) {
96dc20a302Sas200622 		smbsr_errno(sr, rc);
97faa1795aSjb150015 		return (SDRC_ERROR);
98da6c28aaSamw 	}
99da6c28aaSamw 
1007b59d02dSjb150015 	rc = smbsr_encode_result(sr, 5, VAR_BCC, "bw8.wbwC",
101faa1795aSjb150015 	    5, param->rw_count, VAR_BCC, 0x01, param->rw_count, &sr->raw_data);
102da6c28aaSamw 
103faa1795aSjb150015 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
104da6c28aaSamw }
105da6c28aaSamw 
106da6c28aaSamw /*
107da6c28aaSamw  * Lock and read bytes from a file (SMB Core Plus).  The SmbLockAndRead/
108da6c28aaSamw  * SmbLockAndWrite sub-dialect is only valid on disk files: reject any
109da6c28aaSamw  * attempt to use it on non-disk shares.
110da6c28aaSamw  *
111da6c28aaSamw  * The requested count specifies the number of bytes desired.  Offset
112da6c28aaSamw  * specifies the offset in the file of the first byte to be locked then
113da6c28aaSamw  * read. Note that offset is limited to 32 bits, so this client request
114da6c28aaSamw  * is inappropriate for files with 64 bit offsets.
115da6c28aaSamw  *
116da6c28aaSamw  * As with SMB_LOCK_BYTE_RANGE request, if the lock cannot be granted
117da6c28aaSamw  * immediately an error should be returned to the client.  If an error
118da6c28aaSamw  * occurs on the lock, the bytes should not be read.
119da6c28aaSamw  *
120da6c28aaSamw  * On return, count is the number of bytes actually being returned, which
121da6c28aaSamw  * may be less than the count requested only if a read specifies bytes
122da6c28aaSamw  * beyond the current file size.  In this case only the bytes that exist
123da6c28aaSamw  * are returned.  A read completely beyond the end of file results in a
124da6c28aaSamw  * response of length zero.  This is the only circumstance when a zero
125da6c28aaSamw  * length response is generated.  A count returned which is less than the
126da6c28aaSamw  * count requested is the end of file indicator.
127da6c28aaSamw  */
1287b59d02dSjb150015 smb_sdrc_t
129faa1795aSjb150015 smb_pre_lock_and_read(smb_request_t *sr)
130da6c28aaSamw {
131faa1795aSjb150015 	smb_rw_param_t *param;
132da6c28aaSamw 	uint16_t remcnt;
133da6c28aaSamw 	uint32_t off_low;
134faa1795aSjb150015 	int rc;
135faa1795aSjb150015 
136faa1795aSjb150015 	param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
137faa1795aSjb150015 	sr->arg.rw = param;
138faa1795aSjb150015 
139faa1795aSjb150015 	rc = smbsr_decode_vwv(sr, "wwlw", &sr->smb_fid,
140faa1795aSjb150015 	    &param->rw_count, &off_low, &remcnt);
141faa1795aSjb150015 
142faa1795aSjb150015 	param->rw_offset = (uint64_t)off_low;
143faa1795aSjb150015 	param->rw_mincnt = 0;
144faa1795aSjb150015 
145faa1795aSjb150015 	DTRACE_SMB_2(op__LockAndRead__start, smb_request_t *, sr,
146faa1795aSjb150015 	    smb_rw_param_t *, param);
147faa1795aSjb150015 
148faa1795aSjb150015 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
149faa1795aSjb150015 }
150faa1795aSjb150015 
151faa1795aSjb150015 void
152faa1795aSjb150015 smb_post_lock_and_read(smb_request_t *sr)
153faa1795aSjb150015 {
154faa1795aSjb150015 	DTRACE_SMB_2(op__LockAndRead__done, smb_request_t *, sr,
155faa1795aSjb150015 	    smb_rw_param_t *, sr->arg.rw);
156faa1795aSjb150015 
157faa1795aSjb150015 	kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
158faa1795aSjb150015 }
159faa1795aSjb150015 
160faa1795aSjb150015 smb_sdrc_t
161faa1795aSjb150015 smb_com_lock_and_read(smb_request_t *sr)
162faa1795aSjb150015 {
163faa1795aSjb150015 	smb_rw_param_t *param = sr->arg.rw;
164faa1795aSjb150015 	DWORD status;
165da6c28aaSamw 	int rc;
166da6c28aaSamw 
167da6c28aaSamw 	if (STYPE_ISDSK(sr->tid_tree->t_res_type) == 0) {
168dc20a302Sas200622 		smbsr_error(sr, NT_STATUS_ACCESS_DENIED, ERRDOS, ERRnoaccess);
169faa1795aSjb150015 		return (SDRC_ERROR);
170da6c28aaSamw 	}
171da6c28aaSamw 
172da6c28aaSamw 	sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
173da6c28aaSamw 	if (sr->fid_ofile == NULL) {
174dc20a302Sas200622 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
175faa1795aSjb150015 		return (SDRC_ERROR);
176da6c28aaSamw 	}
177da6c28aaSamw 
178*b89a8333Snatalie li - Sun Microsystems - Irvine United States 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
179*b89a8333Snatalie li - Sun Microsystems - Irvine United States 
1806537f381Sas200622 	status = smb_lock_range(sr, param->rw_offset, (uint64_t)param->rw_count,
1816537f381Sas200622 	    UINT_MAX, SMB_LOCK_TYPE_READWRITE);
182faa1795aSjb150015 	if (status != NT_STATUS_SUCCESS) {
183faa1795aSjb150015 		smb_lock_range_error(sr, status);
184faa1795aSjb150015 		return (SDRC_ERROR);
185da6c28aaSamw 	}
186da6c28aaSamw 
187faa1795aSjb150015 	if ((rc = smb_common_read(sr, param)) != 0) {
188dc20a302Sas200622 		smbsr_errno(sr, rc);
189faa1795aSjb150015 		return (SDRC_ERROR);
190da6c28aaSamw 	}
191da6c28aaSamw 
1927b59d02dSjb150015 	rc = smbsr_encode_result(sr, 5, VAR_BCC, "bw8.wbwC",
193faa1795aSjb150015 	    5, param->rw_count, VAR_BCC, 0x1, param->rw_count, &sr->raw_data);
194da6c28aaSamw 
195faa1795aSjb150015 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
196da6c28aaSamw }
197da6c28aaSamw 
198da6c28aaSamw /*
199da6c28aaSamw  * The SMB_COM_READ_RAW protocol is a negotiated option introduced in
200da6c28aaSamw  * SMB Core Plus to maximize performance when reading a large block
201da6c28aaSamw  * of data from a server.  This request was extended in LM 0.12 to
202da6c28aaSamw  * support 64-bit offsets; the server can indicate support by setting
203da6c28aaSamw  * CAP_LARGE_FILES in the negotiated capabilities.
204da6c28aaSamw  *
205da6c28aaSamw  * The client must guarantee that there is (and will be) no other request
206da6c28aaSamw  * to the server for the duration of the SMB_COM_READ_RAW, since the
207da6c28aaSamw  * server response has no header or trailer. To help ensure that there
208da6c28aaSamw  * are no interruptions, we block all I/O for the session during read raw.
209da6c28aaSamw  *
210da6c28aaSamw  * If this is the first SMB request received since we sent an oplock break
211da6c28aaSamw  * to this client, we don't know if it's safe to send the raw data because
212da6c28aaSamw  * the requests may have crossed on the wire and the client may have
213da6c28aaSamw  * interpreted the oplock break as part of the raw data. To avoid problems,
214da6c28aaSamw  * we send a zero length session packet, which will force the client to
215da6c28aaSamw  * retry the read.
216da6c28aaSamw  *
217da6c28aaSamw  * Read errors are handled by sending a zero length response.
218da6c28aaSamw  */
2197b59d02dSjb150015 smb_sdrc_t
220faa1795aSjb150015 smb_pre_read_raw(smb_request_t *sr)
221da6c28aaSamw {
222faa1795aSjb150015 	smb_rw_param_t *param;
223da6c28aaSamw 	uint32_t off_low;
224da6c28aaSamw 	uint32_t off_high;
225da6c28aaSamw 	uint32_t timeout;
226da6c28aaSamw 	int rc;
227da6c28aaSamw 
228faa1795aSjb150015 	param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
229faa1795aSjb150015 	sr->arg.rw = param;
230faa1795aSjb150015 
231da6c28aaSamw 	if (sr->smb_wct == 8) {
232da6c28aaSamw 		rc = smbsr_decode_vwv(sr, "wlwwl2.", &sr->smb_fid,
233faa1795aSjb150015 		    &off_low, &param->rw_count, &param->rw_mincnt,
234da6c28aaSamw 		    &timeout);
235faa1795aSjb150015 		param->rw_offset = (uint64_t)off_low;
236da6c28aaSamw 	} else {
237da6c28aaSamw 		rc = smbsr_decode_vwv(sr, "wlwwl2.l", &sr->smb_fid,
238faa1795aSjb150015 		    &off_low, &param->rw_count, &param->rw_mincnt,
239faa1795aSjb150015 		    &timeout, &off_high);
240faa1795aSjb150015 		param->rw_offset = ((uint64_t)off_high << 32) | off_low;
241da6c28aaSamw 	}
242da6c28aaSamw 
243faa1795aSjb150015 	DTRACE_SMB_2(op__ReadRaw__start, smb_request_t *, sr,
244faa1795aSjb150015 	    smb_rw_param_t *, param);
245da6c28aaSamw 
246faa1795aSjb150015 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
247faa1795aSjb150015 }
248faa1795aSjb150015 
249faa1795aSjb150015 void
250faa1795aSjb150015 smb_post_read_raw(smb_request_t *sr)
251faa1795aSjb150015 {
252faa1795aSjb150015 	DTRACE_SMB_2(op__ReadRaw__done, smb_request_t *, sr,
253faa1795aSjb150015 	    smb_rw_param_t *, sr->arg.rw);
254faa1795aSjb150015 
255faa1795aSjb150015 	kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
256faa1795aSjb150015 }
257faa1795aSjb150015 
258faa1795aSjb150015 smb_sdrc_t
259faa1795aSjb150015 smb_com_read_raw(smb_request_t *sr)
260faa1795aSjb150015 {
261faa1795aSjb150015 	smb_rw_param_t *param = sr->arg.rw;
262faa1795aSjb150015 	smb_node_t *node;
263faa1795aSjb150015 	int rc;
264faa1795aSjb150015 
265faa1795aSjb150015 	switch (sr->session->s_state) {
266faa1795aSjb150015 	case SMB_SESSION_STATE_NEGOTIATED:
267faa1795aSjb150015 		break;
268faa1795aSjb150015 
269faa1795aSjb150015 	case SMB_SESSION_STATE_OPLOCK_BREAKING:
270faa1795aSjb150015 		(void) smb_session_send(sr->session, 0, NULL);
271faa1795aSjb150015 		sr->session->s_state = SMB_SESSION_STATE_NEGOTIATED;
272faa1795aSjb150015 		return (SDRC_NO_REPLY);
273faa1795aSjb150015 
274faa1795aSjb150015 	case SMB_SESSION_STATE_TERMINATED:
275faa1795aSjb150015 	case SMB_SESSION_STATE_DISCONNECTED:
276faa1795aSjb150015 		return (SDRC_NO_REPLY);
277faa1795aSjb150015 
278faa1795aSjb150015 	case SMB_SESSION_STATE_WRITE_RAW_ACTIVE:
279faa1795aSjb150015 	case SMB_SESSION_STATE_CONNECTED:
280faa1795aSjb150015 	case SMB_SESSION_STATE_ESTABLISHED:
281faa1795aSjb150015 	default:
282faa1795aSjb150015 		return (SDRC_DROP_VC);
283faa1795aSjb150015 	}
284faa1795aSjb150015 
285faa1795aSjb150015 	sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
286da6c28aaSamw 	if (sr->fid_ofile == NULL) {
287faa1795aSjb150015 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
288faa1795aSjb150015 		return (SDRC_ERROR);
289da6c28aaSamw 	}
290da6c28aaSamw 
291*b89a8333Snatalie li - Sun Microsystems - Irvine United States 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
292*b89a8333Snatalie li - Sun Microsystems - Irvine United States 
293faa1795aSjb150015 	rc = smb_common_read(sr, param);
294faa1795aSjb150015 
295da6c28aaSamw 	if (STYPE_ISDSK(sr->tid_tree->t_res_type)) {
296da6c28aaSamw 		node = sr->fid_ofile->f_node;
297da6c28aaSamw 		if (node->n_oplock.op_flags & OPLOCK_FLAG_BREAKING) {
298da6c28aaSamw 			rc = EAGAIN;
299da6c28aaSamw 		}
300da6c28aaSamw 	}
301da6c28aaSamw 
302da6c28aaSamw 	if (rc != 0) {
303da6c28aaSamw 		(void) smb_session_send(sr->session, 0, NULL);
304da6c28aaSamw 		m_freem(sr->raw_data.chain);
305da6c28aaSamw 		sr->raw_data.chain = 0;
306da6c28aaSamw 	} else {
307da6c28aaSamw 		(void) smb_session_send(sr->session, 0, &sr->raw_data);
308da6c28aaSamw 	}
309faa1795aSjb150015 
310da6c28aaSamw 	return (SDRC_NO_REPLY);
311da6c28aaSamw }
312da6c28aaSamw 
313da6c28aaSamw /*
314da6c28aaSamw  * Read bytes from a file (SMB Core).  This request was extended in
315da6c28aaSamw  * LM 0.12 to support 64-bit offsets, indicated by sending a wct of
316da6c28aaSamw  * 12 and including additional offset information.
317da6c28aaSamw  */
3187b59d02dSjb150015 smb_sdrc_t
319faa1795aSjb150015 smb_pre_read_andx(smb_request_t *sr)
320da6c28aaSamw {
321faa1795aSjb150015 	smb_rw_param_t *param;
322da6c28aaSamw 	uint32_t off_low;
323da6c28aaSamw 	uint32_t off_high;
324da6c28aaSamw 	uint16_t remcnt;
325da6c28aaSamw 	int rc;
326da6c28aaSamw 
327faa1795aSjb150015 	param = kmem_zalloc(sizeof (smb_rw_param_t), KM_SLEEP);
328faa1795aSjb150015 	sr->arg.rw = param;
329faa1795aSjb150015 
330da6c28aaSamw 	if (sr->smb_wct == 12) {
331faa1795aSjb150015 		rc = smbsr_decode_vwv(sr, "b3.wlw6.wl", &param->rw_andx,
332faa1795aSjb150015 		    &sr->smb_fid, &off_low, &param->rw_count, &remcnt,
333faa1795aSjb150015 		    &off_high);
334da6c28aaSamw 
335faa1795aSjb150015 		param->rw_offset = ((uint64_t)off_high << 32) | off_low;
336da6c28aaSamw 	} else {
337faa1795aSjb150015 		rc = smbsr_decode_vwv(sr, "b3.wlw6.w", &param->rw_andx,
338faa1795aSjb150015 		    &sr->smb_fid, &off_low, &param->rw_count, &remcnt);
339da6c28aaSamw 
340faa1795aSjb150015 		param->rw_offset = (uint64_t)off_low;
341da6c28aaSamw 	}
342da6c28aaSamw 
343faa1795aSjb150015 	param->rw_mincnt = 0;
344da6c28aaSamw 
345faa1795aSjb150015 	DTRACE_SMB_2(op__ReadX__start, smb_request_t *, sr,
346faa1795aSjb150015 	    smb_rw_param_t *, param);
347faa1795aSjb150015 
348faa1795aSjb150015 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
349faa1795aSjb150015 }
350faa1795aSjb150015 
351faa1795aSjb150015 void
352faa1795aSjb150015 smb_post_read_andx(smb_request_t *sr)
353faa1795aSjb150015 {
354faa1795aSjb150015 	DTRACE_SMB_2(op__ReadX__done, smb_request_t *, sr,
355faa1795aSjb150015 	    smb_rw_param_t *, sr->arg.rw);
356faa1795aSjb150015 
357faa1795aSjb150015 	kmem_free(sr->arg.rw, sizeof (smb_rw_param_t));
358faa1795aSjb150015 }
359faa1795aSjb150015 
360faa1795aSjb150015 smb_sdrc_t
361faa1795aSjb150015 smb_com_read_andx(smb_request_t *sr)
362faa1795aSjb150015 {
363faa1795aSjb150015 	smb_rw_param_t *param = sr->arg.rw;
364faa1795aSjb150015 	uint16_t offset2;
365faa1795aSjb150015 	int rc;
366da6c28aaSamw 
367da6c28aaSamw 	sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree, sr->smb_fid);
368da6c28aaSamw 	if (sr->fid_ofile == NULL) {
369dc20a302Sas200622 		smbsr_error(sr, NT_STATUS_INVALID_HANDLE, ERRDOS, ERRbadfid);
370faa1795aSjb150015 		return (SDRC_ERROR);
371da6c28aaSamw 	}
372da6c28aaSamw 
373*b89a8333Snatalie li - Sun Microsystems - Irvine United States 	sr->user_cr = smb_ofile_getcred(sr->fid_ofile);
374*b89a8333Snatalie li - Sun Microsystems - Irvine United States 
375faa1795aSjb150015 	if ((rc = smb_common_read(sr, param)) != 0) {
376dc20a302Sas200622 		smbsr_errno(sr, rc);
377faa1795aSjb150015 		return (SDRC_ERROR);
378da6c28aaSamw 	}
379da6c28aaSamw 
380da6c28aaSamw 	/*
381da6c28aaSamw 	 * Ensure that the next response offset is zero
382da6c28aaSamw 	 * if there is no secondary command.
383da6c28aaSamw 	 */
384faa1795aSjb150015 	offset2 = (param->rw_andx == 0xFF) ? 0 : param->rw_count + 59;
385da6c28aaSamw 
386da6c28aaSamw 	/*
387da6c28aaSamw 	 * The STYPE_IPC response format is different.
388da6c28aaSamw 	 * The unknown value (2) may be to indicate that it
389da6c28aaSamw 	 * is a follow-up to an earlier RPC transaction.
390da6c28aaSamw 	 */
391da6c28aaSamw 	if (STYPE_ISIPC(sr->tid_tree->t_res_type)) {
3927b59d02dSjb150015 		rc = smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.ww10.wbC",
393da6c28aaSamw 		    12,			/* wct */
394faa1795aSjb150015 		    param->rw_andx,	/* Secondary andx command */
395da6c28aaSamw 		    offset2,		/* offset to next */
396da6c28aaSamw 		    0,			/* must be 0 */
397faa1795aSjb150015 		    param->rw_count,	/* data byte count */
398da6c28aaSamw 		    60,			/* Offset from start to data */
399da6c28aaSamw 		    VAR_BCC,		/* BCC marker */
400da6c28aaSamw 		    0x02,		/* unknown */
401da6c28aaSamw 		    &sr->raw_data);
402da6c28aaSamw 	} else {
4037b59d02dSjb150015 		rc = smbsr_encode_result(sr, 12, VAR_BCC, "bb1.ww4.ww10.wC",
404da6c28aaSamw 		    12,			/* wct */
405faa1795aSjb150015 		    param->rw_andx,	/* Secondary andx command */
406da6c28aaSamw 		    offset2,		/* offset to next */
407da6c28aaSamw 		    -1,			/* must be -1 */
408faa1795aSjb150015 		    param->rw_count,	/* data byte count */
409da6c28aaSamw 		    59,			/* Offset from start to data */
410da6c28aaSamw 		    VAR_BCC,		/* BCC marker */
411da6c28aaSamw 		    &sr->raw_data);
412da6c28aaSamw 	}
413da6c28aaSamw 
414faa1795aSjb150015 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
415da6c28aaSamw }
416da6c28aaSamw 
417da6c28aaSamw /*
418da6c28aaSamw  * Common function for reading files or IPC/MSRPC named pipes.  All
419da6c28aaSamw  * protocol read functions should lookup the fid before calling this
420da6c28aaSamw  * function.  We can't move the fid lookup here because lock-and-read
421da6c28aaSamw  * requires the fid to do locking before attempting the read.
422da6c28aaSamw  *
423da6c28aaSamw  * Returns errno values.
424da6c28aaSamw  */
425da6c28aaSamw int
426faa1795aSjb150015 smb_common_read(smb_request_t *sr, smb_rw_param_t *param)
427da6c28aaSamw {
428da6c28aaSamw 	smb_ofile_t *ofile = sr->fid_ofile;
429da6c28aaSamw 	smb_node_t *node;
430faa1795aSjb150015 	smb_vdb_t *vdb = &param->rw_vdb;
431da6c28aaSamw 	struct mbuf *top;
432da6c28aaSamw 	int rc;
433da6c28aaSamw 
434da6c28aaSamw 	vdb->tag = 0;
435da6c28aaSamw 	vdb->uio.uio_iov = &vdb->iovec[0];
436da6c28aaSamw 	vdb->uio.uio_iovcnt = MAX_IOVEC;
437faa1795aSjb150015 	vdb->uio.uio_resid = param->rw_count;
438faa1795aSjb150015 	vdb->uio.uio_loffset = (offset_t)param->rw_offset;
439da6c28aaSamw 	vdb->uio.uio_segflg = UIO_SYSSPACE;
440da6c28aaSamw 
441da6c28aaSamw 	switch (sr->tid_tree->t_res_type & STYPE_MASK) {
442da6c28aaSamw 	case STYPE_DISKTREE:
443da6c28aaSamw 		node = ofile->f_node;
444da6c28aaSamw 
445da6c28aaSamw 		if (node->attr.sa_vattr.va_type != VDIR) {
446faa1795aSjb150015 			rc = smb_lock_range_access(sr, node, param->rw_offset,
447faa1795aSjb150015 			    param->rw_count, B_FALSE);
448da6c28aaSamw 			if (rc != NT_STATUS_SUCCESS) {
449da6c28aaSamw 				rc = ERANGE;
450da6c28aaSamw 				break;
451da6c28aaSamw 			}
452da6c28aaSamw 		}
453da6c28aaSamw 
454da6c28aaSamw 		(void) smb_sync_fsattr(sr, sr->user_cr, node);
455da6c28aaSamw 
456da6c28aaSamw 		sr->raw_data.max_bytes = vdb->uio.uio_resid;
457da6c28aaSamw 		top = smb_mbuf_allocate(&vdb->uio);
458da6c28aaSamw 
459da6c28aaSamw 		rc = smb_fsop_read(sr, sr->user_cr, node, &vdb->uio,
460da6c28aaSamw 		    &node->attr);
461da6c28aaSamw 
462da6c28aaSamw 		sr->raw_data.max_bytes -= vdb->uio.uio_resid;
463da6c28aaSamw 		smb_mbuf_trim(top, sr->raw_data.max_bytes);
464da6c28aaSamw 		MBC_ATTACH_MBUF(&sr->raw_data, top);
465da6c28aaSamw 		break;
466da6c28aaSamw 
467da6c28aaSamw 	case STYPE_IPC:
4683db3f65cSamw 		rc = smb_opipe_read(sr, &vdb->uio);
469da6c28aaSamw 		break;
470da6c28aaSamw 
471da6c28aaSamw 	default:
472da6c28aaSamw 		rc = EACCES;
473da6c28aaSamw 		break;
474da6c28aaSamw 	}
475da6c28aaSamw 
476faa1795aSjb150015 	param->rw_count -= vdb->uio.uio_resid;
477da6c28aaSamw 
478da6c28aaSamw 	if (rc != 0)
479da6c28aaSamw 		return (rc);
480da6c28aaSamw 
481faa1795aSjb150015 	if (param->rw_mincnt != 0 && param->rw_count < param->rw_mincnt) {
482da6c28aaSamw 		/*
483da6c28aaSamw 		 * mincnt is only used by read-raw and is typically
484da6c28aaSamw 		 * zero.  If mincnt is greater than zero and the
485da6c28aaSamw 		 * number of bytes read is less than mincnt, tell
486da6c28aaSamw 		 * the client that we read nothing.
487da6c28aaSamw 		 */
488faa1795aSjb150015 		param->rw_count = 0;
489da6c28aaSamw 	}
490da6c28aaSamw 
491faa1795aSjb150015 	param->rw_offset += param->rw_count;
492da6c28aaSamw 	mutex_enter(&sr->fid_ofile->f_mutex);
493faa1795aSjb150015 	ofile->f_seek_pos = param->rw_offset;
494da6c28aaSamw 	mutex_exit(&sr->fid_ofile->f_mutex);
495da6c28aaSamw 	return (rc);
496da6c28aaSamw }
497