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 2019 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_rw_param_t *param = NULL; 27 smb_ofile_t *of = NULL; 28 smb_vdb_t *vdb = NULL; 29 struct mbuf *m = NULL; 30 uint16_t StructSize; 31 uint8_t Padding; 32 uint8_t DataOff; 33 uint32_t Length; 34 uint64_t Offset; 35 smb2fid_t smb2fid; 36 uint32_t MinCount; 37 uint32_t Channel; 38 uint32_t Remaining; 39 uint16_t ChanInfoOffset; 40 uint16_t ChanInfoLength; 41 uint32_t XferCount; 42 uint32_t status; 43 int rc = 0; 44 45 /* 46 * SMB2 Read request 47 */ 48 rc = smb_mbc_decodef( 49 &sr->smb_data, 50 "wb.lqqqlllww", 51 &StructSize, /* w */ 52 &Padding, /* b. */ 53 &Length, /* l */ 54 &Offset, /* q */ 55 &smb2fid.persistent, /* q */ 56 &smb2fid.temporal, /* q */ 57 &MinCount, /* l */ 58 &Channel, /* l */ 59 &Remaining, /* l */ 60 &ChanInfoOffset, /* w */ 61 &ChanInfoLength); /* w */ 62 if (rc) 63 return (SDRC_ERROR); 64 if (StructSize != 49) 65 return (SDRC_ERROR); 66 67 /* 68 * Setup an smb_rw_param_t which contains the VDB we need. 69 * This is automatically free'd. 70 */ 71 param = smb_srm_zalloc(sr, sizeof (*param)); 72 param->rw_offset = Offset; 73 param->rw_count = Length; 74 /* Note that the dtrace provider uses sr->arg.rw */ 75 sr->arg.rw = param; 76 77 /* 78 * Want FID lookup before the start probe. 79 */ 80 status = smb2sr_lookup_fid(sr, &smb2fid); 81 of = sr->fid_ofile; 82 83 DTRACE_SMB2_START(op__Read, smb_request_t *, sr); /* arg.rw */ 84 85 if (status) 86 goto errout; /* Bad FID */ 87 88 if (Length > smb2_max_rwsize) { 89 status = NT_STATUS_INVALID_PARAMETER; 90 goto errout; 91 } 92 if (MinCount > Length) 93 MinCount = Length; 94 95 vdb = ¶m->rw_vdb; 96 vdb->vdb_tag = 0; 97 vdb->vdb_uio.uio_iov = &vdb->vdb_iovec[0]; 98 vdb->vdb_uio.uio_iovcnt = MAX_IOVEC; 99 vdb->vdb_uio.uio_resid = Length; 100 vdb->vdb_uio.uio_loffset = (offset_t)Offset; 101 vdb->vdb_uio.uio_segflg = UIO_SYSSPACE; 102 vdb->vdb_uio.uio_extflg = UIO_COPY_DEFAULT; 103 104 sr->raw_data.max_bytes = Length; 105 m = smb_mbuf_allocate(&vdb->vdb_uio); 106 107 switch (of->f_tree->t_res_type & STYPE_MASK) { 108 case STYPE_DISKTREE: 109 if (!smb_node_is_dir(of->f_node)) { 110 /* Check for conflicting locks. */ 111 rc = smb_lock_range_access(sr, of->f_node, 112 Offset, Length, B_FALSE); 113 if (rc) { 114 rc = ERANGE; 115 break; 116 } 117 } 118 rc = smb_fsop_read(sr, of->f_cr, of->f_node, of, 119 &vdb->vdb_uio); 120 break; 121 case STYPE_IPC: 122 rc = smb_opipe_read(sr, &vdb->vdb_uio); 123 break; 124 default: 125 case STYPE_PRINTQ: 126 rc = EACCES; 127 break; 128 } 129 status = smb_errno2status(rc); 130 131 /* How much data we moved. */ 132 XferCount = Length - vdb->vdb_uio.uio_resid; 133 134 sr->raw_data.max_bytes = XferCount; 135 smb_mbuf_trim(m, XferCount); 136 MBC_ATTACH_MBUF(&sr->raw_data, m); 137 138 /* 139 * Checking the error return _after_ dealing with 140 * the returned data so that if m was allocated, 141 * it will be free'd via sr->raw_data cleanup. 142 */ 143 errout: 144 sr->smb2_status = status; 145 DTRACE_SMB2_DONE(op__Read, smb_request_t *, sr); /* arg.rw */ 146 if (status) { 147 smb2sr_put_error(sr, status); 148 return (SDRC_SUCCESS); 149 } 150 151 /* 152 * SMB2 Read reply 153 */ 154 DataOff = SMB2_HDR_SIZE + 16; 155 rc = smb_mbc_encodef( 156 &sr->reply, 157 "wb.lllC", 158 17, /* StructSize */ /* w */ 159 DataOff, /* b. */ 160 XferCount, /* l */ 161 0, /* DataRemaining */ /* l */ 162 0, /* reserved */ /* l */ 163 &sr->raw_data); /* C */ 164 if (rc) { 165 sr->smb2_status = NT_STATUS_INTERNAL_ERROR; 166 return (SDRC_ERROR); 167 } 168 169 mutex_enter(&of->f_mutex); 170 of->f_seek_pos = Offset + XferCount; 171 mutex_exit(&of->f_mutex); 172 173 return (SDRC_SUCCESS); 174 } 175