xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_nt_transact_notify_change.c (revision 93bc28dbaee6387120d48b12b3dc1ba5f7418e6e)
1da6c28aaSamw /*
2da6c28aaSamw  * CDDL HEADER START
3da6c28aaSamw  *
4da6c28aaSamw  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
7da6c28aaSamw  *
8da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw  * See the License for the specific language governing permissions
11da6c28aaSamw  * and limitations under the License.
12da6c28aaSamw  *
13da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw  *
19da6c28aaSamw  * CDDL HEADER END
20da6c28aaSamw  */
21148c5f43SAlan Wright 
22da6c28aaSamw /*
23148c5f43SAlan Wright  * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
24*93bc28dbSGordon Ross  * Copyright 2017 Nexenta Systems, Inc.  All rights reserved.
25da6c28aaSamw  */
26da6c28aaSamw 
27da6c28aaSamw /*
28da6c28aaSamw  * File Change Notification (FCN)
29a90cf9f2SGordon Ross  * SMB1 specific part.
30da6c28aaSamw  */
31da6c28aaSamw 
32da6c28aaSamw /*
33da6c28aaSamw  * SMB: nt_transact_notify_change
34da6c28aaSamw  *
35da6c28aaSamw  *  Client Setup Words                 Description
36da6c28aaSamw  *  ================================== =================================
37da6c28aaSamw  *
38da6c28aaSamw  *  ULONG CompletionFilter;            Specifies operation to monitor
39da6c28aaSamw  *  USHORT Fid;                        Fid of directory to monitor
40da6c28aaSamw  *  BOOLEAN WatchTree;                 TRUE = watch all subdirectories too
41da6c28aaSamw  *  UCHAR Reserved;                    MBZ
42da6c28aaSamw  *
43da6c28aaSamw  * This command notifies the client when the directory specified by Fid is
44a90cf9f2SGordon Ross  * modified.  See smb_notify.c for details.
45da6c28aaSamw  *
46a90cf9f2SGordon Ross  * The MaxParameterCount field in the NT transact header determines
47a90cf9f2SGordon Ross  * the size of the buffer used to return change information:
48da6c28aaSamw  *
49da6c28aaSamw  *  Server Response                    Description
50da6c28aaSamw  *  ================================== ================================
51da6c28aaSamw  *  ParameterCount                     # of bytes of change data
52da6c28aaSamw  *  Parameters[ ParameterCount ]       FILE_NOTIFY_INFORMATION
53da6c28aaSamw  *                                      structures
54da6c28aaSamw  *
55a90cf9f2SGordon Ross  * See smb_notify.c for details of FILE_NOTIFY_INFORMATION
56da6c28aaSamw  */
57da6c28aaSamw 
58bbf6f00cSJordan Brown #include <smbsrv/smb_kproto.h>
59da6c28aaSamw 
60faa1795aSjb150015 /*
61da6c28aaSamw  * smb_nt_transact_notify_change
62da6c28aaSamw  *
63ccc71be5SGordon Ross  * Handle and SMB NT transact NOTIFY CHANGE request.
64ccc71be5SGordon Ross  * Basically, wait until "something has changed", and either
65ccc71be5SGordon Ross  * return information about what changed, or return a special
66ccc71be5SGordon Ross  * error telling the client "many things changed".
67ccc71be5SGordon Ross  *
68ccc71be5SGordon Ross  * The implementation uses a per-node list of waiting notify
69ccc71be5SGordon Ross  * requests like this one, each with a blocked worker thead.
70ccc71be5SGordon Ross  * Later, FEM and/or smbsrv events wake these threads, which
71ccc71be5SGordon Ross  * then send the reply to the client.
72da6c28aaSamw  */
737b59d02dSjb150015 smb_sdrc_t
smb_nt_transact_notify_change(smb_request_t * sr,struct smb_xa * xa)74ccc71be5SGordon Ross smb_nt_transact_notify_change(smb_request_t *sr, struct smb_xa *xa)
75da6c28aaSamw {
76bfe5e737SGordon Ross 	mbuf_chain_t		tmp_mbc;
77bfe5e737SGordon Ross 	uint32_t		oBufSize;
78da6c28aaSamw 	uint32_t		CompletionFilter;
79da6c28aaSamw 	unsigned char		WatchTree;
80a90cf9f2SGordon Ross 	uint32_t		status;
81da6c28aaSamw 
823db3f65cSamw 	if (smb_mbc_decodef(&xa->req_setup_mb, "lwb",
83ccc71be5SGordon Ross 	    &CompletionFilter, &sr->smb_fid, &WatchTree) != 0) {
84ccc71be5SGordon Ross 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 0, 0);
85ccc71be5SGordon Ross 		return (SDRC_ERROR);
86ccc71be5SGordon Ross 	}
87da6c28aaSamw 
882c2961f8Sjose borrego 	smbsr_lookup_file(sr);
89bfe5e737SGordon Ross 	if (sr->fid_ofile == NULL) {
90bfe5e737SGordon Ross 		smbsr_error(sr, NT_STATUS_INVALID_PARAMETER, 0, 0);
91bfe5e737SGordon Ross 		return (SDRC_ERROR);
92bfe5e737SGordon Ross 	}
93da6c28aaSamw 
94bfe5e737SGordon Ross 	oBufSize = xa->rep_param_mb.max_bytes;
95bfe5e737SGordon Ross 	CompletionFilter &= FILE_NOTIFY_VALID_MASK;
96bfe5e737SGordon Ross 	if (WatchTree)
97bfe5e737SGordon Ross 		CompletionFilter |= FILE_NOTIFY_CHANGE_EV_SUBDIR;
98da6c28aaSamw 
99ccc71be5SGordon Ross 	/*
100bfe5e737SGordon Ross 	 * Check for events and consume, non-blocking.
101bfe5e737SGordon Ross 	 * Special return STATUS_PENDING means:
102bfe5e737SGordon Ross 	 *   No events; caller must call "act2" next.
103ccc71be5SGordon Ross 	 */
104bfe5e737SGordon Ross 	status = smb_notify_act1(sr, oBufSize, CompletionFilter);
105bfe5e737SGordon Ross 	if (status == NT_STATUS_PENDING) {
106bfe5e737SGordon Ross 		status = smb_notify_act2(sr);
107bfe5e737SGordon Ross 		if (status == NT_STATUS_PENDING) {
108bfe5e737SGordon Ross 			/* See: smb_nt_transact_notify_finish */
109bfe5e737SGordon Ross 			return (SDRC_SR_KEPT);
110bfe5e737SGordon Ross 		}
111bfe5e737SGordon Ross 		/* else: some other error, or even success */
112bfe5e737SGordon Ross 	}
113da6c28aaSamw 
114bfe5e737SGordon Ross 	/*
115bfe5e737SGordon Ross 	 * SMB1 expects an empty trans response after the
116bfe5e737SGordon Ross 	 * FID we're watching is closed.
117bfe5e737SGordon Ross 	 */
118bfe5e737SGordon Ross 	if (status == NT_STATUS_NOTIFY_CLEANUP) {
119bfe5e737SGordon Ross 		status = 0;
120bfe5e737SGordon Ross 		MBC_FLUSH(&sr->raw_data);
121bfe5e737SGordon Ross 	}
122bfe5e737SGordon Ross 
123bfe5e737SGordon Ross 	if (status != 0) {
124bfe5e737SGordon Ross 		smbsr_status(sr, status, 0, 0);
125bfe5e737SGordon Ross 		if (NT_SC_SEVERITY(status) == NT_STATUS_SEVERITY_ERROR)
126bfe5e737SGordon Ross 			return (SDRC_ERROR);
127bfe5e737SGordon Ross 		/* Else continue with NT_STATUS_NOTIFY_ENUM_DIR etc. */
128bfe5e737SGordon Ross 	}
129bfe5e737SGordon Ross 
130bfe5e737SGordon Ross 	/*
131bfe5e737SGordon Ross 	 * The nt_trans call expects the output in rep_param_mb,
132bfe5e737SGordon Ross 	 * but our common code puts it in raw_data.  Move it
133bfe5e737SGordon Ross 	 * where the caller expects it via swaping the two,
134bfe5e737SGordon Ross 	 * which lets the normal cleanup take care of both.
135bfe5e737SGordon Ross 	 */
136bfe5e737SGordon Ross 	tmp_mbc = xa->rep_param_mb;
137bfe5e737SGordon Ross 	xa->rep_param_mb = sr->raw_data;
138bfe5e737SGordon Ross 	sr->raw_data = tmp_mbc;
139da6c28aaSamw 
140a90cf9f2SGordon Ross 	return (SDRC_SUCCESS);
141da6c28aaSamw }
142bfe5e737SGordon Ross 
143bfe5e737SGordon Ross /*
144bfe5e737SGordon Ross  * This is called via taskq_dispatch in smb_notify.c
145bfe5e737SGordon Ross  * to finish up an NT transact notify change request.
146bfe5e737SGordon Ross  */
147bfe5e737SGordon Ross void
smb_nt_transact_notify_finish(void * arg)148bfe5e737SGordon Ross smb_nt_transact_notify_finish(void *arg)
149bfe5e737SGordon Ross {
150bfe5e737SGordon Ross 	smb_request_t	*sr = arg;
151bfe5e737SGordon Ross 	struct smb_xa	*xa;
152bfe5e737SGordon Ross 	smb_disp_stats_t *sds;
153bfe5e737SGordon Ross 	int		total_bytes, n_setup, n_param, n_data;
154bfe5e737SGordon Ross 	int		param_off, param_pad, data_off, data_pad;
155bfe5e737SGordon Ross 	uint32_t	status;
156bfe5e737SGordon Ross 
157bfe5e737SGordon Ross 	SMB_REQ_VALID(sr);
158bfe5e737SGordon Ross 
159bfe5e737SGordon Ross 	/*
160bfe5e737SGordon Ross 	 * Common part of notify, puts data in sr->raw_data
161bfe5e737SGordon Ross 	 */
162bfe5e737SGordon Ross 	status = smb_notify_act3(sr);
163bfe5e737SGordon Ross 
164bfe5e737SGordon Ross 	/*
165bfe5e737SGordon Ross 	 * SMB1 expects an empty trans response after the
166bfe5e737SGordon Ross 	 * FID we're watching is closed.
167bfe5e737SGordon Ross 	 */
168bfe5e737SGordon Ross 	if (status == NT_STATUS_NOTIFY_CLEANUP) {
169bfe5e737SGordon Ross 		status = 0;
170bfe5e737SGordon Ross 		MBC_FLUSH(&sr->raw_data);
171bfe5e737SGordon Ross 	}
172bfe5e737SGordon Ross 
173bfe5e737SGordon Ross 	if (status != 0) {
174bfe5e737SGordon Ross 		smbsr_status(sr, status, 0, 0);
175bfe5e737SGordon Ross 		if (NT_SC_SEVERITY(status) == NT_STATUS_SEVERITY_ERROR) {
176bfe5e737SGordon Ross 			(void) smb_mbc_encodef(&sr->reply, "bwbw",
177bfe5e737SGordon Ross 			    (short)0, 0L, (short)0, 0L);
178bfe5e737SGordon Ross 			goto sendit;
179bfe5e737SGordon Ross 		}
180bfe5e737SGordon Ross 		/* Else continue with NT_STATUS_NOTIFY_ENUM_DIR etc. */
181bfe5e737SGordon Ross 	}
182bfe5e737SGordon Ross 
183bfe5e737SGordon Ross 	/*
184bfe5e737SGordon Ross 	 * setup the NT transact reply
185bfe5e737SGordon Ross 	 *
186bfe5e737SGordon Ross 	 * Note that this is a copy/paste of code from
187bfe5e737SGordon Ross 	 * smb_nt_trans_dispatch(), with minor changes.
188bfe5e737SGordon Ross 	 * Intentionally keeping this similar to the
189bfe5e737SGordon Ross 	 * original rather than hand-optimizing.
190bfe5e737SGordon Ross 	 *
191bfe5e737SGordon Ross 	 * The "setup" and "data" parts of this trans reply
192bfe5e737SGordon Ross 	 * (n_setup, n_data, rep_setup_mb, rep_data_mb) are
193bfe5e737SGordon Ross 	 * always empty.  sr->raw_data replaces rep_param_mb.
194bfe5e737SGordon Ross 	 */
195bfe5e737SGordon Ross 	xa = sr->r_xa;
196bfe5e737SGordon Ross 	n_setup = MBC_LENGTH(&xa->rep_setup_mb);
197bfe5e737SGordon Ross 	n_param = MBC_LENGTH(&sr->raw_data);
198bfe5e737SGordon Ross 	n_data  = MBC_LENGTH(&xa->rep_data_mb);
199bfe5e737SGordon Ross 
200bfe5e737SGordon Ross 	n_setup = (n_setup + 1) / 2;	/* Convert to setup words */
201bfe5e737SGordon Ross 	param_pad = 1;			/* must be one */
202bfe5e737SGordon Ross 	param_off = param_pad + 32 + 37 + (n_setup << 1) + 2;
203bfe5e737SGordon Ross 	/* Pad to 4 bytes */
204bfe5e737SGordon Ross 	data_pad = (4 - ((param_off + n_param) & 3)) % 4;
205bfe5e737SGordon Ross 	/* Param off from hdr */
206bfe5e737SGordon Ross 	data_off = param_off + n_param + data_pad;
207bfe5e737SGordon Ross 	total_bytes = param_pad + n_param + data_pad + n_data;
208bfe5e737SGordon Ross 
209bfe5e737SGordon Ross 	(void) smbsr_encode_result(sr, 18+n_setup, total_bytes,
210bfe5e737SGordon Ross 	    "b3.llllllllbCw#.C#.C",
211bfe5e737SGordon Ross 	    18 + n_setup,	/* wct */
212bfe5e737SGordon Ross 	    n_param,		/* Total Parameter Bytes */
213bfe5e737SGordon Ross 	    n_data,		/* Total Data Bytes */
214bfe5e737SGordon Ross 	    n_param,		/* Total Parameter Bytes this buffer */
215bfe5e737SGordon Ross 	    param_off,		/* Param offset from header start */
216bfe5e737SGordon Ross 	    0,			/* Param displacement */
217bfe5e737SGordon Ross 	    n_data,		/* Total Data Bytes this buffer */
218bfe5e737SGordon Ross 	    data_off,		/* Data offset from header start */
219bfe5e737SGordon Ross 	    0,			/* Data displacement */
220bfe5e737SGordon Ross 	    n_setup,		/* suwcnt */
221bfe5e737SGordon Ross 	    &xa->rep_setup_mb,	/* setup[] */
222bfe5e737SGordon Ross 	    total_bytes,	/* Total data bytes */
223bfe5e737SGordon Ross 	    param_pad,
224bfe5e737SGordon Ross 	    &sr->raw_data,	/* output mbc */
225bfe5e737SGordon Ross 	    data_pad,
226bfe5e737SGordon Ross 	    &xa->rep_data_mb);
227bfe5e737SGordon Ross 
228bfe5e737SGordon Ross sendit:
229*93bc28dbSGordon Ross 	/*
230*93bc28dbSGordon Ross 	 * When smb_nt_transact_notify_change returned SDRC_SR_KEPT
231*93bc28dbSGordon Ross 	 * the dispatcher skipped the "done" probe, so do it now.
232*93bc28dbSGordon Ross 	 * Note: Don't use this probe in response time statistics.
233*93bc28dbSGordon Ross 	 */
234*93bc28dbSGordon Ross 	DTRACE_SMB_DONE(op__NtTransact, smb_request_t *, sr);
235*93bc28dbSGordon Ross 
236bfe5e737SGordon Ross 	sds = &sr->sr_server->sv_disp_stats1[sr->smb_com];
237bfe5e737SGordon Ross 	atomic_add_64(&sds->sdt_txb, (int64_t)sr->reply.chain_offset);
238bfe5e737SGordon Ross 
239bfe5e737SGordon Ross 	smbsr_send_reply(sr);	/* also puts the SMB header. */
240bfe5e737SGordon Ross 	smbsr_cleanup(sr);
241bfe5e737SGordon Ross 
242bfe5e737SGordon Ross 	mutex_enter(&sr->sr_mutex);
243bfe5e737SGordon Ross 	sr->sr_state = SMB_REQ_STATE_COMPLETED;
244bfe5e737SGordon Ross 	mutex_exit(&sr->sr_mutex);
245bfe5e737SGordon Ross 
246bfe5e737SGordon Ross 	smb_request_free(sr);
247bfe5e737SGordon Ross }
248