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-2021 Tintri by DDN, Inc. All rights reserved. 14 */ 15 16 /* 17 * Dispatch function for SMB2_READ 18 * MS-SMB2 sec. 3.3.5.12 19 */ 20 21 #include <smbsrv/smb2_kproto.h> 22 #include <smbsrv/smb_fsops.h> 23 24 extern boolean_t smb_allow_unbuffered; 25 26 smb_sdrc_t 27 smb2_read(smb_request_t *sr) 28 { 29 smb_rw_param_t *param = NULL; 30 smb_ofile_t *of = NULL; 31 smb_vdb_t *vdb = NULL; 32 struct mbuf *m = NULL; 33 uint16_t StructSize; 34 uint8_t Padding; 35 uint8_t Flags; 36 uint8_t DataOff; 37 uint32_t Length; 38 uint64_t Offset; 39 smb2fid_t smb2fid; 40 uint32_t MinCount; 41 uint32_t Channel; 42 uint32_t Remaining; 43 uint16_t ChanInfoOffset; 44 uint16_t ChanInfoLength; 45 uint32_t XferCount = 0; 46 uint32_t status; 47 int rc = 0; 48 boolean_t unbuffered = B_FALSE; 49 int ioflag = 0; 50 51 /* 52 * SMB2 Read request 53 */ 54 rc = smb_mbc_decodef( 55 &sr->smb_data, 56 "wbblqqqlllww", 57 &StructSize, /* w */ 58 &Padding, /* b */ 59 &Flags, /* b */ 60 &Length, /* l */ 61 &Offset, /* q */ 62 &smb2fid.persistent, /* q */ 63 &smb2fid.temporal, /* q */ 64 &MinCount, /* l */ 65 &Channel, /* l */ 66 &Remaining, /* l */ 67 &ChanInfoOffset, /* w */ 68 &ChanInfoLength); /* w */ 69 if (rc) 70 return (SDRC_ERROR); 71 if (StructSize != 49) 72 return (SDRC_ERROR); 73 74 /* 75 * Setup an smb_rw_param_t which contains the VDB we need. 76 * This is automatically free'd. 77 */ 78 param = smb_srm_zalloc(sr, sizeof (*param)); 79 param->rw_offset = Offset; 80 param->rw_count = Length; 81 /* Note that the dtrace provider uses sr->arg.rw */ 82 sr->arg.rw = param; 83 84 /* 85 * Want FID lookup before the start probe. 86 */ 87 status = smb2sr_lookup_fid(sr, &smb2fid); 88 of = sr->fid_ofile; 89 90 DTRACE_SMB2_START(op__Read, smb_request_t *, sr); /* arg.rw */ 91 92 if (status != 0) 93 goto done; /* Bad FID */ 94 95 /* 96 * Short-circuit zero-byte read, otherwise could panic 97 * setting up buffers in smb_mbuf_allocate etc. 98 */ 99 if (Length == 0) 100 goto done; 101 102 if (Length > smb2_max_rwsize) { 103 status = NT_STATUS_INVALID_PARAMETER; 104 goto done; 105 } 106 if (MinCount > Length) 107 MinCount = Length; 108 109 vdb = ¶m->rw_vdb; 110 vdb->vdb_tag = 0; 111 vdb->vdb_uio.uio_iov = &vdb->vdb_iovec[0]; 112 vdb->vdb_uio.uio_iovcnt = MAX_IOVEC; 113 vdb->vdb_uio.uio_resid = Length; 114 vdb->vdb_uio.uio_loffset = (offset_t)Offset; 115 vdb->vdb_uio.uio_segflg = UIO_SYSSPACE; 116 vdb->vdb_uio.uio_extflg = UIO_COPY_DEFAULT; 117 118 sr->raw_data.max_bytes = Length; 119 m = smb_mbuf_allocate(&vdb->vdb_uio); 120 121 /* 122 * Unbuffered refers to the MS-FSA Read argument by the same name. 123 * It indicates that the cache for this range should be flushed to disk, 124 * and data read directly from disk, bypassing the cache. 125 * We don't allow that degree of cache management. 126 * Translate this directly as FRSYNC, 127 * which should at least flush the cache first. 128 */ 129 130 if (smb_allow_unbuffered && 131 (Flags & SMB2_READFLAG_READ_UNBUFFERED) != 0) { 132 unbuffered = B_TRUE; 133 ioflag = FRSYNC; 134 } 135 136 switch (of->f_tree->t_res_type & STYPE_MASK) { 137 case STYPE_DISKTREE: 138 if (!smb_node_is_dir(of->f_node)) { 139 /* Check for conflicting locks. */ 140 rc = smb_lock_range_access(sr, of->f_node, 141 Offset, Length, B_FALSE); 142 if (rc) { 143 rc = ERANGE; 144 break; 145 } 146 } 147 rc = smb_fsop_read(sr, of->f_cr, of->f_node, of, 148 &vdb->vdb_uio, ioflag); 149 break; 150 case STYPE_IPC: 151 if (unbuffered) 152 rc = EINVAL; 153 else 154 rc = smb_opipe_read(sr, &vdb->vdb_uio); 155 break; 156 default: 157 case STYPE_PRINTQ: 158 rc = EACCES; 159 break; 160 } 161 status = smb_errno2status(rc); 162 163 /* How much data we moved. */ 164 XferCount = Length - vdb->vdb_uio.uio_resid; 165 166 sr->raw_data.max_bytes = XferCount; 167 smb_mbuf_trim(m, XferCount); 168 MBC_ATTACH_MBUF(&sr->raw_data, m); 169 170 /* 171 * [MS-SMB2] If the read returns fewer bytes than specified by 172 * the MinimumCount field of the request, the server MUST fail 173 * the request with STATUS_END_OF_FILE 174 */ 175 if (status == 0 && XferCount < MinCount) 176 status = NT_STATUS_END_OF_FILE; 177 178 /* 179 * Checking the error return _after_ dealing with 180 * the returned data so that if m was allocated, 181 * it will be free'd via sr->raw_data cleanup. 182 */ 183 done: 184 sr->smb2_status = status; 185 DTRACE_SMB2_DONE(op__Read, smb_request_t *, sr); /* arg.rw */ 186 if (status) { 187 smb2sr_put_error(sr, status); 188 return (SDRC_SUCCESS); 189 } 190 191 /* 192 * SMB2 Read reply 193 */ 194 DataOff = SMB2_HDR_SIZE + 16; 195 rc = smb_mbc_encodef( 196 &sr->reply, 197 "wb.lllC", 198 17, /* StructSize */ /* w */ 199 DataOff, /* b. */ 200 XferCount, /* l */ 201 0, /* DataRemaining */ /* l */ 202 0, /* reserved */ /* l */ 203 &sr->raw_data); /* C */ 204 if (rc) { 205 sr->smb2_status = NT_STATUS_INTERNAL_ERROR; 206 return (SDRC_ERROR); 207 } 208 209 mutex_enter(&of->f_mutex); 210 of->f_seek_pos = Offset + XferCount; 211 mutex_exit(&of->f_mutex); 212 213 return (SDRC_SUCCESS); 214 } 215