1*a90cf9f2SGordon Ross /* 2*a90cf9f2SGordon Ross * This file and its contents are supplied under the terms of the 3*a90cf9f2SGordon Ross * Common Development and Distribution License ("CDDL"), version 1.0. 4*a90cf9f2SGordon Ross * You may only use this file in accordance with the terms of version 5*a90cf9f2SGordon Ross * 1.0 of the CDDL. 6*a90cf9f2SGordon Ross * 7*a90cf9f2SGordon Ross * A full copy of the text of the CDDL should have accompanied this 8*a90cf9f2SGordon Ross * source. A copy of the CDDL is also available via the Internet at 9*a90cf9f2SGordon Ross * http://www.illumos.org/license/CDDL. 10*a90cf9f2SGordon Ross */ 11*a90cf9f2SGordon Ross 12*a90cf9f2SGordon Ross /* 13*a90cf9f2SGordon Ross * Copyright 2014 Nexenta Systems, Inc. All rights reserved. 14*a90cf9f2SGordon Ross */ 15*a90cf9f2SGordon Ross 16*a90cf9f2SGordon Ross /* 17*a90cf9f2SGordon Ross * Dispatch function for SMB2_WRITE 18*a90cf9f2SGordon Ross */ 19*a90cf9f2SGordon Ross 20*a90cf9f2SGordon Ross #include <smbsrv/smb2_kproto.h> 21*a90cf9f2SGordon Ross #include <smbsrv/smb_fsops.h> 22*a90cf9f2SGordon Ross 23*a90cf9f2SGordon Ross smb_sdrc_t 24*a90cf9f2SGordon Ross smb2_write(smb_request_t *sr) 25*a90cf9f2SGordon Ross { 26*a90cf9f2SGordon Ross smb_ofile_t *of = NULL; 27*a90cf9f2SGordon Ross smb_vdb_t *vdb = NULL; 28*a90cf9f2SGordon Ross uint16_t StructSize; 29*a90cf9f2SGordon Ross uint16_t DataOff; 30*a90cf9f2SGordon Ross uint32_t Length; 31*a90cf9f2SGordon Ross uint64_t Offset; 32*a90cf9f2SGordon Ross smb2fid_t smb2fid; 33*a90cf9f2SGordon Ross uint32_t Channel; 34*a90cf9f2SGordon Ross uint32_t Remaining; 35*a90cf9f2SGordon Ross uint16_t ChanInfoOffset; 36*a90cf9f2SGordon Ross uint16_t ChanInfoLength; 37*a90cf9f2SGordon Ross uint32_t Flags; 38*a90cf9f2SGordon Ross uint32_t XferCount; 39*a90cf9f2SGordon Ross uint32_t status; 40*a90cf9f2SGordon Ross int data_chain_off, skip; 41*a90cf9f2SGordon Ross int stability = 0; 42*a90cf9f2SGordon Ross int rc = 0; 43*a90cf9f2SGordon Ross 44*a90cf9f2SGordon Ross /* 45*a90cf9f2SGordon Ross * SMB2 Write request 46*a90cf9f2SGordon Ross */ 47*a90cf9f2SGordon Ross rc = smb_mbc_decodef( 48*a90cf9f2SGordon Ross &sr->smb_data, 49*a90cf9f2SGordon Ross "wwlqqqllwwl", 50*a90cf9f2SGordon Ross &StructSize, /* w */ 51*a90cf9f2SGordon Ross &DataOff, /* w */ 52*a90cf9f2SGordon Ross &Length, /* l */ 53*a90cf9f2SGordon Ross &Offset, /* q */ 54*a90cf9f2SGordon Ross &smb2fid.persistent, /* q */ 55*a90cf9f2SGordon Ross &smb2fid.temporal, /* q */ 56*a90cf9f2SGordon Ross &Channel, /* l */ 57*a90cf9f2SGordon Ross &Remaining, /* l */ 58*a90cf9f2SGordon Ross &ChanInfoOffset, /* w */ 59*a90cf9f2SGordon Ross &ChanInfoLength, /* w */ 60*a90cf9f2SGordon Ross &Flags); /* l */ 61*a90cf9f2SGordon Ross if (rc) 62*a90cf9f2SGordon Ross return (SDRC_ERROR); 63*a90cf9f2SGordon Ross if (StructSize != 49) 64*a90cf9f2SGordon Ross return (SDRC_ERROR); 65*a90cf9f2SGordon Ross 66*a90cf9f2SGordon Ross status = smb2sr_lookup_fid(sr, &smb2fid); 67*a90cf9f2SGordon Ross if (status) { 68*a90cf9f2SGordon Ross smb2sr_put_error(sr, status); 69*a90cf9f2SGordon Ross return (SDRC_SUCCESS); 70*a90cf9f2SGordon Ross } 71*a90cf9f2SGordon Ross of = sr->fid_ofile; 72*a90cf9f2SGordon Ross 73*a90cf9f2SGordon Ross if (Length > smb2_max_rwsize) { 74*a90cf9f2SGordon Ross smb2sr_put_error(sr, NT_STATUS_INVALID_PARAMETER); 75*a90cf9f2SGordon Ross return (SDRC_SUCCESS); 76*a90cf9f2SGordon Ross } 77*a90cf9f2SGordon Ross 78*a90cf9f2SGordon Ross /* 79*a90cf9f2SGordon Ross * Skip any padding before the write data. 80*a90cf9f2SGordon Ross */ 81*a90cf9f2SGordon Ross data_chain_off = sr->smb2_cmd_hdr + DataOff; 82*a90cf9f2SGordon Ross skip = data_chain_off - sr->smb_data.chain_offset; 83*a90cf9f2SGordon Ross if (skip < 0) { 84*a90cf9f2SGordon Ross smb2sr_put_error(sr, NT_STATUS_INVALID_PARAMETER); 85*a90cf9f2SGordon Ross return (SDRC_SUCCESS); 86*a90cf9f2SGordon Ross } 87*a90cf9f2SGordon Ross if (skip > 0) { 88*a90cf9f2SGordon Ross (void) smb_mbc_decodef(&sr->smb_data, "#.", skip); 89*a90cf9f2SGordon Ross } 90*a90cf9f2SGordon Ross 91*a90cf9f2SGordon Ross /* This is automatically free'd. */ 92*a90cf9f2SGordon Ross vdb = smb_srm_zalloc(sr, sizeof (*vdb)); 93*a90cf9f2SGordon Ross rc = smb_mbc_decodef(&sr->smb_data, "#B", Length, vdb); 94*a90cf9f2SGordon Ross if (rc != 0 || vdb->vdb_len != Length) { 95*a90cf9f2SGordon Ross smb2sr_put_error(sr, NT_STATUS_INVALID_PARAMETER); 96*a90cf9f2SGordon Ross return (SDRC_SUCCESS); 97*a90cf9f2SGordon Ross } 98*a90cf9f2SGordon Ross vdb->vdb_uio.uio_loffset = (offset_t)Offset; 99*a90cf9f2SGordon Ross 100*a90cf9f2SGordon Ross XferCount = 0; 101*a90cf9f2SGordon Ross if (Length == 0) 102*a90cf9f2SGordon Ross goto doreply; 103*a90cf9f2SGordon Ross 104*a90cf9f2SGordon Ross switch (of->f_tree->t_res_type & STYPE_MASK) { 105*a90cf9f2SGordon Ross case STYPE_DISKTREE: 106*a90cf9f2SGordon Ross case STYPE_PRINTQ: 107*a90cf9f2SGordon Ross if (!smb_node_is_dir(of->f_node)) { 108*a90cf9f2SGordon Ross /* Check for conflicting locks. */ 109*a90cf9f2SGordon Ross rc = smb_lock_range_access(sr, of->f_node, 110*a90cf9f2SGordon Ross Offset, Length, B_TRUE); 111*a90cf9f2SGordon Ross if (rc) { 112*a90cf9f2SGordon Ross rc = ERANGE; 113*a90cf9f2SGordon Ross break; 114*a90cf9f2SGordon Ross } 115*a90cf9f2SGordon Ross } 116*a90cf9f2SGordon Ross if ((Flags & SMB2_WRITEFLAG_WRITE_THROUGH) || 117*a90cf9f2SGordon Ross (of->f_node->flags & NODE_FLAGS_WRITE_THROUGH)) { 118*a90cf9f2SGordon Ross stability = FSYNC; 119*a90cf9f2SGordon Ross } 120*a90cf9f2SGordon Ross rc = smb_fsop_write(sr, of->f_cr, of->f_node, 121*a90cf9f2SGordon Ross &vdb->vdb_uio, &XferCount, stability); 122*a90cf9f2SGordon Ross if (rc) 123*a90cf9f2SGordon Ross break; 124*a90cf9f2SGordon Ross of->f_written = B_TRUE; 125*a90cf9f2SGordon Ross if (!smb_node_is_dir(of->f_node)) 126*a90cf9f2SGordon Ross smb_oplock_break_levelII(of->f_node); 127*a90cf9f2SGordon Ross break; 128*a90cf9f2SGordon Ross 129*a90cf9f2SGordon Ross case STYPE_IPC: 130*a90cf9f2SGordon Ross rc = smb_opipe_write(sr, &vdb->vdb_uio); 131*a90cf9f2SGordon Ross if (rc == 0) 132*a90cf9f2SGordon Ross XferCount = Length; 133*a90cf9f2SGordon Ross break; 134*a90cf9f2SGordon Ross 135*a90cf9f2SGordon Ross default: 136*a90cf9f2SGordon Ross rc = EACCES; 137*a90cf9f2SGordon Ross break; 138*a90cf9f2SGordon Ross } 139*a90cf9f2SGordon Ross 140*a90cf9f2SGordon Ross if (rc) { 141*a90cf9f2SGordon Ross smb2sr_put_errno(sr, rc); 142*a90cf9f2SGordon Ross return (SDRC_SUCCESS); 143*a90cf9f2SGordon Ross } 144*a90cf9f2SGordon Ross 145*a90cf9f2SGordon Ross /* 146*a90cf9f2SGordon Ross * SMB2 Write reply 147*a90cf9f2SGordon Ross */ 148*a90cf9f2SGordon Ross doreply: 149*a90cf9f2SGordon Ross DataOff = SMB2_HDR_SIZE + 16; 150*a90cf9f2SGordon Ross rc = smb_mbc_encodef( 151*a90cf9f2SGordon Ross &sr->reply, "wwlll", 152*a90cf9f2SGordon Ross 17, /* StructSize */ /* w */ 153*a90cf9f2SGordon Ross 0, /* reserved */ /* w */ 154*a90cf9f2SGordon Ross XferCount, /* l */ 155*a90cf9f2SGordon Ross 0, /* DataRemaining */ /* l */ 156*a90cf9f2SGordon Ross 0); /* Channel Info */ /* l */ 157*a90cf9f2SGordon Ross if (rc) 158*a90cf9f2SGordon Ross return (SDRC_ERROR); 159*a90cf9f2SGordon Ross 160*a90cf9f2SGordon Ross mutex_enter(&of->f_mutex); 161*a90cf9f2SGordon Ross of->f_seek_pos = Offset + XferCount; 162*a90cf9f2SGordon Ross mutex_exit(&of->f_mutex); 163*a90cf9f2SGordon Ross 164*a90cf9f2SGordon Ross return (SDRC_SUCCESS); 165*a90cf9f2SGordon Ross } 166