xref: /titanic_51/usr/src/uts/common/fs/smbsrv/smb2_write.c (revision a90cf9f29973990687fa61de9f1f6ea22e924e40)
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