xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb2_read.c (revision b327cd3f3b4dab4f29e7140159b1e01ed2ceef2a)
1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
14  */
15 
16 /*
17  * Dispatch function for SMB2_READ
18  */
19 
20 #include <smbsrv/smb2_kproto.h>
21 #include <smbsrv/smb_fsops.h>
22 
23 smb_sdrc_t
24 smb2_read(smb_request_t *sr)
25 {
26 	smb_ofile_t *of = NULL;
27 	smb_vdb_t *vdb = NULL;
28 	struct mbuf *m = NULL;
29 	uint16_t StructSize;
30 	uint8_t Padding;
31 	uint8_t DataOff;
32 	uint32_t Length;
33 	uint64_t Offset;
34 	smb2fid_t smb2fid;
35 	uint32_t MinCount;
36 	uint32_t Channel;
37 	uint32_t Remaining;
38 	uint16_t ChanInfoOffset;
39 	uint16_t ChanInfoLength;
40 	uint32_t XferCount;
41 	uint32_t status;
42 	int rc = 0;
43 
44 	/*
45 	 * SMB2 Read request
46 	 */
47 	rc = smb_mbc_decodef(
48 	    &sr->smb_data,
49 	    "wb.lqqqlllww",
50 	    &StructSize,		/* w */
51 	    &Padding,			/* b. */
52 	    &Length,			/* l */
53 	    &Offset,			/* q */
54 	    &smb2fid.persistent,	/* q */
55 	    &smb2fid.temporal,		/* q */
56 	    &MinCount,			/* l */
57 	    &Channel,			/* l */
58 	    &Remaining,			/* l */
59 	    &ChanInfoOffset,		/* w */
60 	    &ChanInfoLength);		/* w */
61 	if (rc)
62 		return (SDRC_ERROR);
63 	if (StructSize != 49)
64 		return (SDRC_ERROR);
65 
66 	status = smb2sr_lookup_fid(sr, &smb2fid);
67 	if (status) {
68 		smb2sr_put_error(sr, status);
69 		return (SDRC_SUCCESS);
70 	}
71 	of = sr->fid_ofile;
72 
73 	if (Length > smb2_max_rwsize) {
74 		smb2sr_put_error(sr, NT_STATUS_INVALID_PARAMETER);
75 		return (SDRC_SUCCESS);
76 	}
77 	if (MinCount > Length)
78 		MinCount = Length;
79 
80 	/* This is automatically free'd. */
81 	vdb = smb_srm_zalloc(sr, sizeof (*vdb));
82 	vdb->vdb_tag = 0;
83 	vdb->vdb_uio.uio_iov = &vdb->vdb_iovec[0];
84 	vdb->vdb_uio.uio_iovcnt = MAX_IOVEC;
85 	vdb->vdb_uio.uio_resid = Length;
86 	vdb->vdb_uio.uio_loffset = (offset_t)Offset;
87 	vdb->vdb_uio.uio_segflg = UIO_SYSSPACE;
88 	vdb->vdb_uio.uio_extflg = UIO_COPY_DEFAULT;
89 
90 	sr->raw_data.max_bytes = Length;
91 	m = smb_mbuf_allocate(&vdb->vdb_uio);
92 
93 	switch (of->f_tree->t_res_type & STYPE_MASK) {
94 	case STYPE_DISKTREE:
95 		if (!smb_node_is_dir(of->f_node)) {
96 			/* Check for conflicting locks. */
97 			rc = smb_lock_range_access(sr, of->f_node,
98 			    Offset, Length, B_FALSE);
99 			if (rc) {
100 				rc = ERANGE;
101 				break;
102 			}
103 		}
104 		rc = smb_fsop_read(sr, of->f_cr, of->f_node, &vdb->vdb_uio);
105 		break;
106 	case STYPE_IPC:
107 		rc = smb_opipe_read(sr, &vdb->vdb_uio);
108 		break;
109 	default:
110 	case STYPE_PRINTQ:
111 		rc = EACCES;
112 		break;
113 	}
114 
115 	/* How much data we moved. */
116 	XferCount = Length - vdb->vdb_uio.uio_resid;
117 
118 	sr->raw_data.max_bytes = XferCount;
119 	smb_mbuf_trim(m, XferCount);
120 	MBC_ATTACH_MBUF(&sr->raw_data, m);
121 
122 	/*
123 	 * Checking the error return _after_ dealing with
124 	 * the returned data so that if m was allocated,
125 	 * it will be free'd via sr->raw_data cleanup.
126 	 */
127 	if (rc) {
128 		smb2sr_put_errno(sr, rc);
129 		return (SDRC_SUCCESS);
130 	}
131 
132 	/*
133 	 * SMB2 Read reply
134 	 */
135 	DataOff = SMB2_HDR_SIZE + 16;
136 	rc = smb_mbc_encodef(
137 	    &sr->reply,
138 	    "wb.lllC",
139 	    17,	/* StructSize */	/* w */
140 	    DataOff,			/* b. */
141 	    XferCount,			/* l */
142 	    0, /* DataRemaining */	/* l */
143 	    0, /* reserved */		/* l */
144 	    &sr->raw_data);		/* C */
145 	if (rc)
146 		return (SDRC_ERROR);
147 
148 	mutex_enter(&of->f_mutex);
149 	of->f_seek_pos = Offset + XferCount;
150 	mutex_exit(&of->f_mutex);
151 
152 	return (SDRC_SUCCESS);
153 }
154