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