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