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