xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_common_transact.c (revision 3ad684d66b78e06edd37e2c4fd3b3949f095194b)
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  */
21da6c28aaSamw /*
22dc20a302Sas200622  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23da6c28aaSamw  * Use is subject to license terms.
24da6c28aaSamw  *
25da6c28aaSamw  */
26da6c28aaSamw 
27da6c28aaSamw #pragma ident	"%Z%%M%	%I%	%E% SMI"
28da6c28aaSamw 
29da6c28aaSamw #include <smbsrv/smb_incl.h>
30da6c28aaSamw #include <smbsrv/smb_fsops.h>
31da6c28aaSamw #include <smbsrv/oem.h>
32da6c28aaSamw #include <smbsrv/nmpipes.h>
33da6c28aaSamw #include <smbsrv/mailslot.h>
34da6c28aaSamw #include <smbsrv/lmerr.h>
35da6c28aaSamw #include <smbsrv/nterror.h>
36da6c28aaSamw 
37da6c28aaSamw /*
38da6c28aaSamw  * count of bytes in server response packet
39da6c28aaSamw  * except parameters and data. Note that setup
40da6c28aaSamw  * word count is zero.
41da6c28aaSamw  */
42da6c28aaSamw #define	RESP_HEADER_LEN		24
43da6c28aaSamw 
44da6c28aaSamw /*
45da6c28aaSamw  * NB. I started by using common functions for transaction/transaction2
46da6c28aaSamw  * and transaction_secondary/transaction2_secondary because they
47da6c28aaSamw  * are respectively so similar. However, it turned out to be a bad
48da6c28aaSamw  * idea because of quirky differences. Be sure if you modify one
49da6c28aaSamw  * of these four functions to check and see if the modification should
50da6c28aaSamw  * be applied to its peer.
51da6c28aaSamw  */
52da6c28aaSamw 
537b59d02dSjb150015 static int smb_trans_ready(struct smb_xa *);
547b59d02dSjb150015 static smb_sdrc_t smb_trans_dispatch(struct smb_request *, struct smb_xa *);
557b59d02dSjb150015 static smb_sdrc_t smb_trans2_dispatch(struct smb_request *, struct smb_xa *);
567b59d02dSjb150015 static smb_sdrc_t smb_nt_transact_query_quota(struct smb_request *,
577b59d02dSjb150015     struct smb_xa *);
58da6c28aaSamw 
597b59d02dSjb150015 smb_sdrc_t
60faa1795aSjb150015 smb_pre_transaction(smb_request_t *sr)
61faa1795aSjb150015 {
62faa1795aSjb150015 	DTRACE_SMB_1(op__Transaction__start, smb_request_t *, sr);
63faa1795aSjb150015 	return (SDRC_SUCCESS);
64faa1795aSjb150015 }
65faa1795aSjb150015 
66faa1795aSjb150015 void
67faa1795aSjb150015 smb_post_transaction(smb_request_t *sr)
68faa1795aSjb150015 {
69faa1795aSjb150015 	DTRACE_SMB_1(op__Transaction__done, smb_request_t *, sr);
70faa1795aSjb150015 }
71faa1795aSjb150015 
72faa1795aSjb150015 smb_sdrc_t
73faa1795aSjb150015 smb_com_transaction(smb_request_t *sr)
74da6c28aaSamw {
75da6c28aaSamw 	int		rc;
76da6c28aaSamw 	unsigned char	msrcnt, suwcnt;
77da6c28aaSamw 	uint16_t	tpscnt, tdscnt, mprcnt, mdrcnt, flags;
78da6c28aaSamw 	uint16_t	pscnt, psoff, dscnt, dsoff;
79da6c28aaSamw 	uint32_t	timeo;
80da6c28aaSamw 	struct smb_xa *xa;
81da6c28aaSamw 	char *stn;
82da6c28aaSamw 	int ready;
83da6c28aaSamw 
84da6c28aaSamw 	rc = smbsr_decode_vwv(sr, SMB_TRANSHDR_ED_FMT,
85da6c28aaSamw 	    &tpscnt, &tdscnt, &mprcnt, &mdrcnt, &msrcnt, &flags,
86da6c28aaSamw 	    &timeo, &pscnt, &psoff, &dscnt, &dsoff, &suwcnt);
87da6c28aaSamw 
887b59d02dSjb150015 	if (rc != 0)
89faa1795aSjb150015 		return (SDRC_ERROR);
90da6c28aaSamw 
91da6c28aaSamw 	xa = smb_xa_create(sr->session, sr, tpscnt, tdscnt, mprcnt, mdrcnt,
92da6c28aaSamw 	    msrcnt, suwcnt);
93da6c28aaSamw 	if (xa == NULL) {
94dc20a302Sas200622 		smbsr_error(sr, 0, ERRSRV, ERRnoroom);
95faa1795aSjb150015 		return (SDRC_ERROR);
96da6c28aaSamw 	}
97da6c28aaSamw 
98da6c28aaSamw 	/* Should be some alignment stuff here in SMB? */
99da6c28aaSamw 	if (sr->smb_flg2 & SMB_FLAGS2_UNICODE) {
100da6c28aaSamw 		rc = smbsr_decode_data(sr, "%.U", sr, &stn);
101da6c28aaSamw 	} else {
102da6c28aaSamw 		rc = smbsr_decode_data(sr, "%s", sr,  &stn);
103da6c28aaSamw 	}
104da6c28aaSamw 	if (rc != 0) {
105da6c28aaSamw 		smb_xa_rele(sr->session, xa);
106faa1795aSjb150015 		return (SDRC_ERROR);
107da6c28aaSamw 	}
108da6c28aaSamw 	xa->xa_smb_trans_name = MEM_STRDUP("smb", stn);
109da6c28aaSamw 
110da6c28aaSamw 	xa->smb_flags  = flags;
111da6c28aaSamw 	xa->smb_timeout = timeo;
112da6c28aaSamw 	xa->req_disp_param = pscnt;
113da6c28aaSamw 	xa->req_disp_data  = dscnt;
114da6c28aaSamw 
115da6c28aaSamw 	if (MBC_SHADOW_CHAIN(&xa->req_setup_mb, &sr->smb_vwv,
116da6c28aaSamw 	    sr->smb_vwv.chain_offset, suwcnt * 2)) {
117da6c28aaSamw 		smb_xa_rele(sr->session, xa);
118dc20a302Sas200622 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
119faa1795aSjb150015 		return (SDRC_ERROR);
120da6c28aaSamw 	}
121da6c28aaSamw 	if (MBC_SHADOW_CHAIN(&xa->req_param_mb, &sr->command, psoff, pscnt)) {
122da6c28aaSamw 		smb_xa_rele(sr->session, xa);
123dc20a302Sas200622 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
124faa1795aSjb150015 		return (SDRC_ERROR);
125da6c28aaSamw 	}
126da6c28aaSamw 	if (MBC_SHADOW_CHAIN(&xa->req_data_mb, &sr->command, dsoff, dscnt)) {
127da6c28aaSamw 		smb_xa_rele(sr->session, xa);
128dc20a302Sas200622 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
129faa1795aSjb150015 		return (SDRC_ERROR);
130da6c28aaSamw 	}
131da6c28aaSamw 
132da6c28aaSamw 	ready = smb_trans_ready(xa);
133da6c28aaSamw 
134da6c28aaSamw 	if (smb_xa_open(xa)) {
135da6c28aaSamw 		smb_xa_rele(sr->session, xa);
136dc20a302Sas200622 		smbsr_error(sr, 0, ERRDOS, ERRsrverror);
137faa1795aSjb150015 		return (SDRC_ERROR);
138da6c28aaSamw 	}
139da6c28aaSamw 	sr->r_xa = xa;
140da6c28aaSamw 
141da6c28aaSamw 	if (!ready) {
1427b59d02dSjb150015 		rc = smbsr_encode_empty_result(sr);
143faa1795aSjb150015 		return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
144da6c28aaSamw 	}
145da6c28aaSamw 
146da6c28aaSamw 	if (!smb_xa_complete(xa)) {
147da6c28aaSamw 		smb_xa_close(xa);
148dc20a302Sas200622 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
149faa1795aSjb150015 		return (SDRC_ERROR);
150da6c28aaSamw 	}
151da6c28aaSamw 
152da6c28aaSamw 	return (smb_trans_dispatch(sr, xa));
153da6c28aaSamw }
154da6c28aaSamw 
1557b59d02dSjb150015 smb_sdrc_t
156faa1795aSjb150015 smb_pre_transaction_secondary(smb_request_t *sr)
157faa1795aSjb150015 {
158faa1795aSjb150015 	DTRACE_SMB_1(op__TransactionSecondary__start, smb_request_t *, sr);
159faa1795aSjb150015 	return (SDRC_SUCCESS);
160faa1795aSjb150015 }
161faa1795aSjb150015 
162faa1795aSjb150015 void
163faa1795aSjb150015 smb_post_transaction_secondary(smb_request_t *sr)
164faa1795aSjb150015 {
165faa1795aSjb150015 	DTRACE_SMB_1(op__TransactionSecondary__done, smb_request_t *, sr);
166faa1795aSjb150015 }
167faa1795aSjb150015 
168faa1795aSjb150015 smb_sdrc_t
169faa1795aSjb150015 smb_com_transaction_secondary(smb_request_t *sr)
170da6c28aaSamw {
171da6c28aaSamw 	uint16_t tpscnt, tdscnt, pscnt, psdisp;
172da6c28aaSamw 	uint16_t dscnt, dsoff, dsdisp, psoff;
173da6c28aaSamw 	smb_xa_t *xa;
174da6c28aaSamw 	int rc;
175da6c28aaSamw 
176da6c28aaSamw 	if ((xa = smbsr_lookup_xa(sr)) == 0) {
177dc20a302Sas200622 		smbsr_error(sr, 0, ERRSRV, ERRsrverror);
178faa1795aSjb150015 		return (SDRC_ERROR);
179da6c28aaSamw 	}
180da6c28aaSamw 
181da6c28aaSamw 	if (sr->session->signing.flags & SMB_SIGNING_ENABLED) {
182da6c28aaSamw 		if (smb_sign_check_secondary(sr, xa->reply_seqnum) != 0) {
183dc20a302Sas200622 			smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
184da6c28aaSamw 			    ERRDOS, ERRnoaccess);
185faa1795aSjb150015 			return (SDRC_ERROR);
186da6c28aaSamw 		}
187da6c28aaSamw 	}
188da6c28aaSamw 
189da6c28aaSamw 	if (xa->smb_com != SMB_COM_TRANSACTION) {
190da6c28aaSamw 		return (SDRC_DROP_VC);
191da6c28aaSamw 	}
192da6c28aaSamw 
193da6c28aaSamw 	rc = smbsr_decode_vwv(sr, SMB_TRANSSHDR_ED_FMT, &tpscnt, &tdscnt,
194da6c28aaSamw 	    &pscnt, &psoff, &psdisp, &dscnt, &dsoff, &dsdisp);
195da6c28aaSamw 
1967b59d02dSjb150015 	if (rc != 0)
197faa1795aSjb150015 		return (SDRC_ERROR);
198da6c28aaSamw 
199da6c28aaSamw 	mutex_enter(&xa->xa_mutex);
200da6c28aaSamw 	xa->smb_tpscnt = tpscnt;	/* might have shrunk */
201da6c28aaSamw 	xa->smb_tdscnt = tdscnt;	/* might have shrunk */
202da6c28aaSamw 	xa->req_disp_param = psdisp+pscnt;
203da6c28aaSamw 	xa->req_disp_data  = dsdisp+dscnt;
204da6c28aaSamw 
205da6c28aaSamw 	if (MBC_SHADOW_CHAIN(&xa->req_param_mb, &sr->command, psoff, pscnt)) {
206da6c28aaSamw 		mutex_exit(&xa->xa_mutex);
207da6c28aaSamw 		smb_xa_close(xa);
208dc20a302Sas200622 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
209faa1795aSjb150015 		return (SDRC_ERROR);
210da6c28aaSamw 	}
211da6c28aaSamw 	if (MBC_SHADOW_CHAIN(&xa->req_data_mb, &sr->command, dsoff, dscnt)) {
212da6c28aaSamw 		mutex_exit(&xa->xa_mutex);
213da6c28aaSamw 		smb_xa_close(xa);
214dc20a302Sas200622 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
215faa1795aSjb150015 		return (SDRC_ERROR);
216da6c28aaSamw 	}
217da6c28aaSamw 	mutex_exit(&xa->xa_mutex);
218da6c28aaSamw 
219da6c28aaSamw 	if (!smb_trans_ready(xa))
220da6c28aaSamw 		return (SDRC_NO_REPLY);
221da6c28aaSamw 
222da6c28aaSamw 	if (!smb_xa_complete(xa))
223da6c28aaSamw 		return (SDRC_NO_REPLY);
224da6c28aaSamw 
225da6c28aaSamw 	return (smb_trans_dispatch(sr, xa));
226da6c28aaSamw }
227da6c28aaSamw 
2287b59d02dSjb150015 smb_sdrc_t
229faa1795aSjb150015 smb_pre_ioctl(smb_request_t *sr)
230faa1795aSjb150015 {
231faa1795aSjb150015 	DTRACE_SMB_1(op__Ioctl__start, smb_request_t *, sr);
232faa1795aSjb150015 	return (SDRC_SUCCESS);
233faa1795aSjb150015 }
234faa1795aSjb150015 
235faa1795aSjb150015 void
236faa1795aSjb150015 smb_post_ioctl(smb_request_t *sr)
237faa1795aSjb150015 {
238faa1795aSjb150015 	DTRACE_SMB_1(op__Ioctl__done, smb_request_t *, sr);
239faa1795aSjb150015 }
240faa1795aSjb150015 
241faa1795aSjb150015 smb_sdrc_t
242faa1795aSjb150015 smb_com_ioctl(smb_request_t *sr)
243da6c28aaSamw {
244da6c28aaSamw 	uint16_t fid, category, function, tpscnt, tdscnt, mprcnt;
245da6c28aaSamw 	uint16_t mdrcnt, pscnt, pdoff, dscnt, dsoff;
246da6c28aaSamw 	uint32_t timeout;
247da6c28aaSamw 	int rc;
248da6c28aaSamw 
249da6c28aaSamw 	rc = smbsr_decode_vwv(sr, "wwwwwwwl2.wwww", &fid, &category, &function,
250da6c28aaSamw 	    &tpscnt, &tdscnt, &mprcnt, &mdrcnt, &timeout, &pscnt,
251da6c28aaSamw 	    &pdoff, &dscnt, &dsoff);
252da6c28aaSamw 
2537b59d02dSjb150015 	if (rc != 0)
254faa1795aSjb150015 		return (SDRC_ERROR);
255da6c28aaSamw 
256faa1795aSjb150015 	return (SDRC_NOT_IMPLEMENTED);
257da6c28aaSamw }
258da6c28aaSamw 
259faa1795aSjb150015 smb_sdrc_t
260faa1795aSjb150015 smb_pre_transaction2(smb_request_t *sr)
261da6c28aaSamw {
262faa1795aSjb150015 	DTRACE_SMB_1(op__Transaction2__start, smb_request_t *, sr);
263faa1795aSjb150015 	return (SDRC_SUCCESS);
264faa1795aSjb150015 }
265faa1795aSjb150015 
266faa1795aSjb150015 void
267faa1795aSjb150015 smb_post_transaction2(smb_request_t *sr)
268faa1795aSjb150015 {
269faa1795aSjb150015 	DTRACE_SMB_1(op__Transaction2__done, smb_request_t *, sr);
270da6c28aaSamw }
271da6c28aaSamw 
2727b59d02dSjb150015 smb_sdrc_t
273da6c28aaSamw smb_com_transaction2(struct smb_request *sr)
274da6c28aaSamw {
275da6c28aaSamw 	unsigned char	msrcnt, suwcnt;
276da6c28aaSamw 	uint16_t	tpscnt, tdscnt, mprcnt, mdrcnt, flags;
277da6c28aaSamw 	uint16_t	pscnt, psoff, dscnt, dsoff;
278da6c28aaSamw 	uint32_t	timeo;
279da6c28aaSamw 	smb_xa_t *xa;
280da6c28aaSamw 	int ready;
281da6c28aaSamw 	int rc;
282da6c28aaSamw 
283da6c28aaSamw 	rc = smbsr_decode_vwv(sr, SMB_TRANSHDR_ED_FMT, &tpscnt, &tdscnt,
284da6c28aaSamw 	    &mprcnt, &mdrcnt, &msrcnt, &flags, &timeo, &pscnt, &psoff, &dscnt,
285da6c28aaSamw 	    &dsoff, &suwcnt);
286da6c28aaSamw 
2877b59d02dSjb150015 	if (rc != 0)
288faa1795aSjb150015 		return (SDRC_ERROR);
289da6c28aaSamw 
290da6c28aaSamw 	xa = smb_xa_create(sr->session, sr, tpscnt, tdscnt, mprcnt, mdrcnt,
291da6c28aaSamw 	    msrcnt, suwcnt);
292da6c28aaSamw 	if (xa == 0) {
293dc20a302Sas200622 		smbsr_error(sr, 0, ERRSRV, ERRnoroom);
294faa1795aSjb150015 		return (SDRC_ERROR);
295da6c28aaSamw 	}
296da6c28aaSamw 
297da6c28aaSamw 	xa->smb_flags  = flags;
298da6c28aaSamw 	xa->smb_timeout = timeo;
299da6c28aaSamw 	xa->req_disp_param = pscnt;
300da6c28aaSamw 	xa->req_disp_data  = dscnt;
301da6c28aaSamw 
302da6c28aaSamw 	if (MBC_SHADOW_CHAIN(&xa->req_setup_mb, &sr->smb_vwv,
303da6c28aaSamw 	    sr->smb_vwv.chain_offset, suwcnt*2)) {
304da6c28aaSamw 		smb_xa_rele(sr->session, xa);
305dc20a302Sas200622 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
306faa1795aSjb150015 		return (SDRC_ERROR);
307da6c28aaSamw 	}
308da6c28aaSamw 	if (MBC_SHADOW_CHAIN(&xa->req_param_mb, &sr->command, psoff, pscnt)) {
309da6c28aaSamw 		smb_xa_rele(sr->session, xa);
310dc20a302Sas200622 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
311faa1795aSjb150015 		return (SDRC_ERROR);
312da6c28aaSamw 	}
313da6c28aaSamw 	if (MBC_SHADOW_CHAIN(&xa->req_data_mb, &sr->command, dsoff, dscnt)) {
314da6c28aaSamw 		smb_xa_rele(sr->session, xa);
315dc20a302Sas200622 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
316faa1795aSjb150015 		return (SDRC_ERROR);
317da6c28aaSamw 	}
318da6c28aaSamw 
319da6c28aaSamw 	ready = smb_trans_ready(xa);
320da6c28aaSamw 
321da6c28aaSamw 	if (smb_xa_open(xa)) {
322da6c28aaSamw 		smb_xa_rele(sr->session, xa);
323dc20a302Sas200622 		smbsr_error(sr, 0, ERRDOS, ERRsrverror);
324faa1795aSjb150015 		return (SDRC_ERROR);
325da6c28aaSamw 	}
326da6c28aaSamw 	sr->r_xa = xa;
327da6c28aaSamw 
328da6c28aaSamw 	if (!ready) {
3297b59d02dSjb150015 		rc = smbsr_encode_empty_result(sr);
330faa1795aSjb150015 		return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
331da6c28aaSamw 	}
332da6c28aaSamw 
333da6c28aaSamw 	if (!smb_xa_complete(xa)) {
334da6c28aaSamw 		smb_xa_close(xa);
335dc20a302Sas200622 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
336faa1795aSjb150015 		return (SDRC_ERROR);
337da6c28aaSamw 	}
338da6c28aaSamw 
339da6c28aaSamw 	return (smb_trans2_dispatch(sr, xa));
340da6c28aaSamw }
341da6c28aaSamw 
3427b59d02dSjb150015 smb_sdrc_t
343faa1795aSjb150015 smb_pre_transaction2_secondary(smb_request_t *sr)
344faa1795aSjb150015 {
345faa1795aSjb150015 	DTRACE_SMB_1(op__Transaction2Secondary__start, smb_request_t *, sr);
346faa1795aSjb150015 	return (SDRC_SUCCESS);
347faa1795aSjb150015 }
348faa1795aSjb150015 
349faa1795aSjb150015 void
350faa1795aSjb150015 smb_post_transaction2_secondary(smb_request_t *sr)
351faa1795aSjb150015 {
352faa1795aSjb150015 	DTRACE_SMB_1(op__Transaction2Secondary__done, smb_request_t *, sr);
353faa1795aSjb150015 }
354faa1795aSjb150015 
355faa1795aSjb150015 smb_sdrc_t
356faa1795aSjb150015 smb_com_transaction2_secondary(smb_request_t *sr)
357da6c28aaSamw {
358da6c28aaSamw 	uint16_t tpscnt, tdscnt, fid;
359da6c28aaSamw 	uint16_t pscnt, psoff, psdisp, dscnt, dsoff, dsdisp;
360da6c28aaSamw 	smb_xa_t *xa;
361da6c28aaSamw 	int rc;
362da6c28aaSamw 
363da6c28aaSamw 	if ((xa = smbsr_lookup_xa(sr)) == 0) {
364dc20a302Sas200622 		smbsr_error(sr, 0, ERRSRV, ERRsrverror);
365faa1795aSjb150015 		return (SDRC_ERROR);
366da6c28aaSamw 	}
367da6c28aaSamw 
368da6c28aaSamw 	if (sr->session->signing.flags & SMB_SIGNING_ENABLED) {
369da6c28aaSamw 		if (smb_sign_check_secondary(sr, xa->reply_seqnum) != 0) {
370dc20a302Sas200622 			smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
371da6c28aaSamw 			    ERRDOS, ERRnoaccess);
372faa1795aSjb150015 			return (SDRC_ERROR);
373da6c28aaSamw 		}
374da6c28aaSamw 	}
375da6c28aaSamw 
376da6c28aaSamw 	if (xa->smb_com != SMB_COM_TRANSACTION2) {
377da6c28aaSamw 		return (SDRC_DROP_VC);
378da6c28aaSamw 	}
379da6c28aaSamw 
380da6c28aaSamw 	rc = smbsr_decode_vwv(sr, SMB_TRANS2SHDR_ED_FMT, &tpscnt, &tdscnt,
381da6c28aaSamw 	    &pscnt, &psoff, &psdisp, &dscnt, &dsoff, &dsdisp, &fid);
382da6c28aaSamw 
3837b59d02dSjb150015 	if (rc != 0)
384faa1795aSjb150015 		return (SDRC_ERROR);
385da6c28aaSamw 
386da6c28aaSamw 	mutex_enter(&xa->xa_mutex);
387da6c28aaSamw 	xa->smb_tpscnt = tpscnt;	/* might have shrunk */
388da6c28aaSamw 	xa->smb_tdscnt = tdscnt;	/* might have shrunk */
389da6c28aaSamw 	xa->xa_smb_fid = fid;		/* overwrite rules? */
390da6c28aaSamw 	xa->req_disp_param = psdisp + pscnt;
391da6c28aaSamw 	xa->req_disp_data  = dsdisp + dscnt;
392da6c28aaSamw 
393da6c28aaSamw 	if (MBC_SHADOW_CHAIN(&xa->req_param_mb, &sr->command, psoff, pscnt)) {
394da6c28aaSamw 		mutex_exit(&xa->xa_mutex);
395da6c28aaSamw 		smb_xa_close(xa);
396dc20a302Sas200622 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
397faa1795aSjb150015 		return (SDRC_ERROR);
398da6c28aaSamw 	}
399da6c28aaSamw 	if (MBC_SHADOW_CHAIN(&xa->req_data_mb, &sr->command, dsoff, dscnt)) {
400da6c28aaSamw 		mutex_exit(&xa->xa_mutex);
401da6c28aaSamw 		smb_xa_close(xa);
402dc20a302Sas200622 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
403faa1795aSjb150015 		return (SDRC_ERROR);
404da6c28aaSamw 	}
405da6c28aaSamw 	mutex_exit(&xa->xa_mutex);
406da6c28aaSamw 
407da6c28aaSamw 	if (!smb_trans_ready(xa))
408da6c28aaSamw 		return (SDRC_NO_REPLY);
409da6c28aaSamw 
410da6c28aaSamw 	if (!smb_xa_complete(xa))
411da6c28aaSamw 		return (SDRC_NO_REPLY);
412da6c28aaSamw 
413da6c28aaSamw 	return (smb_trans2_dispatch(sr, xa));
414da6c28aaSamw }
415da6c28aaSamw 
4167b59d02dSjb150015 static smb_sdrc_t
417da6c28aaSamw smb_nt_trans_dispatch(struct smb_request *sr, struct smb_xa *xa)
418da6c28aaSamw {
419da6c28aaSamw 	int rc;
420da6c28aaSamw 	int total_bytes, n_setup, n_param, n_data;
421da6c28aaSamw 	int param_off, param_pad, data_off, data_pad;
422da6c28aaSamw 
423da6c28aaSamw 	n_setup = (xa->smb_msrcnt < 200) ? xa->smb_msrcnt : 200;
424da6c28aaSamw 	n_setup++;
425da6c28aaSamw 	n_setup = n_setup & ~0x0001;
426da6c28aaSamw 	n_param = (xa->smb_mprcnt < smb_maxbufsize)
427da6c28aaSamw 	    ? xa->smb_mprcnt : smb_maxbufsize;
428da6c28aaSamw 	n_param++;
429da6c28aaSamw 	n_param = n_param & ~0x0001;
430da6c28aaSamw 	rc = smb_maxbufsize - (SMBHEADERSIZE + 28 + n_setup + n_param);
431da6c28aaSamw 	n_data = (xa->smb_mdrcnt < rc) ? xa->smb_mdrcnt : rc;
432da6c28aaSamw 	MBC_INIT(&xa->rep_setup_mb, n_setup * 2);
433da6c28aaSamw 	MBC_INIT(&xa->rep_param_mb, n_param);
434da6c28aaSamw 	MBC_INIT(&xa->rep_data_mb, n_data);
435da6c28aaSamw 
436da6c28aaSamw 	switch (xa->smb_func) {
437da6c28aaSamw 	case NT_TRANSACT_CREATE:
438faa1795aSjb150015 		if ((rc = smb_pre_nt_transact_create(sr, xa)) == 0)
439da6c28aaSamw 			rc = smb_nt_transact_create(sr, xa);
440faa1795aSjb150015 		smb_post_nt_transact_create(sr, xa);
441da6c28aaSamw 		break;
442da6c28aaSamw 	case NT_TRANSACT_NOTIFY_CHANGE:
443da6c28aaSamw 		rc = smb_nt_transact_notify_change(sr, xa);
444da6c28aaSamw 		break;
445da6c28aaSamw 	case NT_TRANSACT_QUERY_SECURITY_DESC:
446da6c28aaSamw 		rc = smb_nt_transact_query_security_info(sr, xa);
447da6c28aaSamw 		break;
448da6c28aaSamw 	case NT_TRANSACT_SET_SECURITY_DESC:
449da6c28aaSamw 		rc = smb_nt_transact_set_security_info(sr, xa);
450da6c28aaSamw 		break;
451da6c28aaSamw 	case NT_TRANSACT_IOCTL:
452da6c28aaSamw 		rc = smb_nt_transact_ioctl(sr, xa);
453da6c28aaSamw 		break;
454da6c28aaSamw 
455da6c28aaSamw 	case NT_TRANSACT_QUERY_QUOTA:
456da6c28aaSamw 		(void) smb_nt_transact_query_quota(sr, xa);
457dc20a302Sas200622 		smbsr_error(sr, 0, ERRSRV, ERRaccess);
458faa1795aSjb150015 		return (SDRC_ERROR);
459da6c28aaSamw 
460da6c28aaSamw 	case NT_TRANSACT_SET_QUOTA:
461dc20a302Sas200622 		smbsr_error(sr, 0, ERRSRV, ERRaccess);
462faa1795aSjb150015 		return (SDRC_ERROR);
463da6c28aaSamw 
464da6c28aaSamw 	default:
465dc20a302Sas200622 		smbsr_error(sr, 0, ERRSRV, ERRsmbcmd);
466faa1795aSjb150015 		return (SDRC_ERROR);
467da6c28aaSamw 	}
468da6c28aaSamw 
469da6c28aaSamw 	switch (rc) {
470faa1795aSjb150015 	case SDRC_SUCCESS:
471da6c28aaSamw 		break;
472da6c28aaSamw 
473da6c28aaSamw 	case SDRC_DROP_VC:
474da6c28aaSamw 	case SDRC_NO_REPLY:
475faa1795aSjb150015 	case SDRC_ERROR:
476da6c28aaSamw 		return (rc);
477da6c28aaSamw 
478faa1795aSjb150015 	case SDRC_NOT_IMPLEMENTED:
479dc20a302Sas200622 		smbsr_error(sr, 0, ERRSRV, ERRsmbcmd);
480faa1795aSjb150015 		return (SDRC_ERROR);
481da6c28aaSamw 
482da6c28aaSamw 	default:
483da6c28aaSamw 		break;
484da6c28aaSamw 	}
485da6c28aaSamw 
486da6c28aaSamw 	n_setup = MBC_LENGTH(&xa->rep_setup_mb);
487da6c28aaSamw 	n_param = MBC_LENGTH(&xa->rep_param_mb);
488da6c28aaSamw 	n_data  = MBC_LENGTH(&xa->rep_data_mb);
489da6c28aaSamw 
490da6c28aaSamw 	if (xa->smb_msrcnt < n_setup ||
491da6c28aaSamw 	    xa->smb_mprcnt < n_param ||
492da6c28aaSamw 	    xa->smb_mdrcnt < n_data) {
493dc20a302Sas200622 		smbsr_error(sr, 0, ERRSRV, ERRsmbcmd);
494faa1795aSjb150015 		return (SDRC_ERROR);
495da6c28aaSamw 	}
496da6c28aaSamw 
497da6c28aaSamw 	/* neato, blast it over there */
498da6c28aaSamw 
499da6c28aaSamw 	n_setup = (n_setup + 1) / 2;		/* Conver to setup words */
500da6c28aaSamw 	param_pad = 1;				/* must be one */
501da6c28aaSamw 	param_off = param_pad + 32 + 37 + (n_setup << 1) + 2;
502da6c28aaSamw 	data_pad = (4 - ((param_off + n_param) & 3)) % 4; /* Pad to 4 byte */
503da6c28aaSamw 	data_off = param_off + n_param + data_pad; /* Param off from hdr */
504da6c28aaSamw 	total_bytes = param_pad + n_param + data_pad + n_data;
505da6c28aaSamw 
5067b59d02dSjb150015 	rc = smbsr_encode_result(sr, 18+n_setup, total_bytes,
507da6c28aaSamw 	    "b 3. llllllllb C w #. C #. C",
508da6c28aaSamw 	    18 + n_setup,		/* wct */
509da6c28aaSamw 	    n_param,			/* Total Parameter Bytes */
510da6c28aaSamw 	    n_data,			/* Total Data Bytes */
511da6c28aaSamw 	    n_param,			/* Total Parameter Bytes this buffer */
512da6c28aaSamw 	    param_off,			/* Param offset from header start */
513da6c28aaSamw 	    0,				/* Param displacement */
514da6c28aaSamw 	    n_data,			/* Total Data Bytes this buffer */
515da6c28aaSamw 	    data_off,			/* Data offset from header start */
516da6c28aaSamw 	    0,				/* Data displacement */
517da6c28aaSamw 	    n_setup,			/* suwcnt */
518da6c28aaSamw 	    &xa->rep_setup_mb,		/* setup[] */
519da6c28aaSamw 	    total_bytes,		/* Total data bytes */
520da6c28aaSamw 	    param_pad,
521da6c28aaSamw 	    &xa->rep_param_mb,
522da6c28aaSamw 	    data_pad,
523da6c28aaSamw 	    &xa->rep_data_mb);
524faa1795aSjb150015 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
525da6c28aaSamw }
526da6c28aaSamw 
527da6c28aaSamw 
528da6c28aaSamw /*
529da6c28aaSamw  * smb_nt_transact_query_quota
530da6c28aaSamw  *
5317b59d02dSjb150015  * There are 16 parameter bytes: fid, flags and 12 zero bytes.
532da6c28aaSamw  */
5337b59d02dSjb150015 static smb_sdrc_t
534da6c28aaSamw smb_nt_transact_query_quota(struct smb_request *sr, struct smb_xa *xa)
535da6c28aaSamw {
536da6c28aaSamw 	uint16_t fid;
537da6c28aaSamw 	uint16_t flags;
538da6c28aaSamw 
5397b59d02dSjb150015 	if (smb_decode_mbc(&xa->req_param_mb, "%ww", sr, &fid, &flags))
540faa1795aSjb150015 		return (SDRC_ERROR);
541da6c28aaSamw 
542faa1795aSjb150015 	return (SDRC_SUCCESS);
543da6c28aaSamw }
544da6c28aaSamw 
545faa1795aSjb150015 smb_sdrc_t
546faa1795aSjb150015 smb_pre_nt_transact(smb_request_t *sr)
547faa1795aSjb150015 {
548faa1795aSjb150015 	DTRACE_SMB_1(op__NtTransact__start, smb_request_t *, sr);
549faa1795aSjb150015 	return (SDRC_SUCCESS);
550faa1795aSjb150015 }
551faa1795aSjb150015 
552faa1795aSjb150015 void
553faa1795aSjb150015 smb_post_nt_transact(smb_request_t *sr)
554faa1795aSjb150015 {
555faa1795aSjb150015 	DTRACE_SMB_1(op__NtTransact__done, smb_request_t *, sr);
556faa1795aSjb150015 }
557da6c28aaSamw 
5587b59d02dSjb150015 smb_sdrc_t
559da6c28aaSamw smb_com_nt_transact(struct smb_request *sr)
560da6c28aaSamw {
561da6c28aaSamw 	uint16_t	Function;
562da6c28aaSamw 	unsigned char	MaxSetupCount, SetupCount;
563da6c28aaSamw 	uint32_t	TotalParameterCount, TotalDataCount;
564da6c28aaSamw 	uint32_t	MaxParameterCount, MaxDataCount, pscnt;
565da6c28aaSamw 	uint32_t	psoff, dscnt, dsoff;
566da6c28aaSamw 	smb_xa_t *xa;
567da6c28aaSamw 	int ready;
568da6c28aaSamw 	int rc;
569da6c28aaSamw 
570da6c28aaSamw 	rc = smbsr_decode_vwv(sr, SMB_NT_TRANSHDR_ED_FMT, &MaxSetupCount,
571da6c28aaSamw 	    &TotalParameterCount, &TotalDataCount, &MaxParameterCount,
572da6c28aaSamw 	    &MaxDataCount, &pscnt, &psoff, &dscnt,
573da6c28aaSamw 	    &dsoff, &SetupCount, &Function);
574da6c28aaSamw 
5757b59d02dSjb150015 	if (rc != 0)
576faa1795aSjb150015 		return (SDRC_ERROR);
577da6c28aaSamw 
578da6c28aaSamw 	xa = smb_xa_create(sr->session, sr, TotalParameterCount, TotalDataCount,
579da6c28aaSamw 	    MaxParameterCount, MaxDataCount, MaxSetupCount, SetupCount);
580da6c28aaSamw 	if (xa == 0) {
581dc20a302Sas200622 		smbsr_error(sr, 0, ERRSRV, ERRnoroom);
582faa1795aSjb150015 		return (SDRC_ERROR);
583da6c28aaSamw 	}
584da6c28aaSamw 
585da6c28aaSamw 	xa->smb_flags  = 0;
586da6c28aaSamw 	xa->smb_timeout = 0;
587da6c28aaSamw 	xa->smb_func = Function;
588da6c28aaSamw 	xa->req_disp_param = pscnt;
589da6c28aaSamw 	xa->req_disp_data  = dscnt;
590da6c28aaSamw 
591da6c28aaSamw 	if (MBC_SHADOW_CHAIN(&xa->req_setup_mb, &sr->smb_vwv,
592da6c28aaSamw 	    sr->smb_vwv.chain_offset, SetupCount * 2)) {
593da6c28aaSamw 		smb_xa_rele(sr->session, xa);
594dc20a302Sas200622 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
595faa1795aSjb150015 		return (SDRC_ERROR);
596da6c28aaSamw 	}
597da6c28aaSamw 	if (MBC_SHADOW_CHAIN(&xa->req_param_mb, &sr->command, psoff, pscnt)) {
598da6c28aaSamw 		smb_xa_rele(sr->session, xa);
599dc20a302Sas200622 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
600faa1795aSjb150015 		return (SDRC_ERROR);
601da6c28aaSamw 	}
602da6c28aaSamw 	if (MBC_SHADOW_CHAIN(&xa->req_data_mb, &sr->command, dsoff, dscnt)) {
603da6c28aaSamw 		smb_xa_rele(sr->session, xa);
604dc20a302Sas200622 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
605faa1795aSjb150015 		return (SDRC_ERROR);
606da6c28aaSamw 	}
607da6c28aaSamw 
608da6c28aaSamw 	ready = smb_trans_ready(xa);
609da6c28aaSamw 
610da6c28aaSamw 	if (smb_xa_open(xa)) {
611da6c28aaSamw 		smb_xa_rele(sr->session, xa);
612dc20a302Sas200622 		smbsr_error(sr, 0, ERRDOS, ERRsrverror);
613faa1795aSjb150015 		return (SDRC_ERROR);
614da6c28aaSamw 	}
615da6c28aaSamw 	sr->r_xa = xa;
616da6c28aaSamw 
617da6c28aaSamw 	if (!ready) {
6187b59d02dSjb150015 		rc = smbsr_encode_empty_result(sr);
619faa1795aSjb150015 		return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
620da6c28aaSamw 	}
621da6c28aaSamw 
622da6c28aaSamw 	if (!smb_xa_complete(xa)) {
623da6c28aaSamw 		smb_xa_close(xa);
624dc20a302Sas200622 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
625faa1795aSjb150015 		return (SDRC_ERROR);
626da6c28aaSamw 	}
627da6c28aaSamw 
628da6c28aaSamw 	return (smb_nt_trans_dispatch(sr, xa));
629da6c28aaSamw }
630da6c28aaSamw 
631faa1795aSjb150015 smb_sdrc_t
632faa1795aSjb150015 smb_pre_nt_transact_secondary(smb_request_t *sr)
633faa1795aSjb150015 {
634faa1795aSjb150015 	DTRACE_SMB_1(op__NtTransactSecondary__start, smb_request_t *, sr);
635faa1795aSjb150015 	return (SDRC_SUCCESS);
636faa1795aSjb150015 }
637faa1795aSjb150015 
638faa1795aSjb150015 void
639faa1795aSjb150015 smb_post_nt_transact_secondary(smb_request_t *sr)
640faa1795aSjb150015 {
641faa1795aSjb150015 	DTRACE_SMB_1(op__NtTransactSecondary__done, smb_request_t *, sr);
642faa1795aSjb150015 }
643da6c28aaSamw 
6447b59d02dSjb150015 smb_sdrc_t
645da6c28aaSamw smb_com_nt_transact_secondary(struct smb_request *sr)
646da6c28aaSamw {
647da6c28aaSamw 	uint16_t tpscnt, tdscnt, fid;
648da6c28aaSamw 	uint16_t pscnt, psoff, psdisp, dscnt, dsoff, dsdisp;
649da6c28aaSamw 	smb_xa_t *xa;
650da6c28aaSamw 	int rc;
651da6c28aaSamw 
652da6c28aaSamw 	if ((xa = smbsr_lookup_xa(sr)) == 0) {
653dc20a302Sas200622 		smbsr_error(sr, 0, ERRSRV, ERRsrverror);
654faa1795aSjb150015 		return (SDRC_ERROR);
655da6c28aaSamw 	}
656da6c28aaSamw 
657da6c28aaSamw 	if (sr->session->signing.flags & SMB_SIGNING_ENABLED) {
658da6c28aaSamw 		if (smb_sign_check_secondary(sr, xa->reply_seqnum) != 0) {
659dc20a302Sas200622 			smbsr_error(sr, NT_STATUS_ACCESS_DENIED,
660da6c28aaSamw 			    ERRDOS, ERRnoaccess);
661faa1795aSjb150015 			return (SDRC_ERROR);
662da6c28aaSamw 		}
663da6c28aaSamw 	}
664da6c28aaSamw 
665da6c28aaSamw 	if (xa->smb_com != SMB_COM_TRANSACTION2) {
666da6c28aaSamw 		return (SDRC_DROP_VC);
667da6c28aaSamw 	}
668da6c28aaSamw 
669da6c28aaSamw 	rc = smbsr_decode_vwv(sr, SMB_TRANS2SHDR_ED_FMT, &tpscnt, &tdscnt,
670da6c28aaSamw 	    &pscnt, &psoff, &psdisp, &dscnt, &dsoff, &dsdisp, &fid);
671da6c28aaSamw 
6727b59d02dSjb150015 	if (rc != 0)
673faa1795aSjb150015 		return (SDRC_ERROR);
674da6c28aaSamw 
675da6c28aaSamw 	mutex_enter(&xa->xa_mutex);
676da6c28aaSamw 	xa->smb_tpscnt = tpscnt;	/* might have shrunk */
677da6c28aaSamw 	xa->smb_tdscnt = tdscnt;	/* might have shrunk */
678da6c28aaSamw 	xa->xa_smb_fid = fid;		/* overwrite rules? */
679da6c28aaSamw 	xa->req_disp_param = psdisp+pscnt;
680da6c28aaSamw 	xa->req_disp_data  = dsdisp+dscnt;
681da6c28aaSamw 
682da6c28aaSamw 	if (MBC_SHADOW_CHAIN(&xa->req_param_mb, &sr->command, psoff, pscnt)) {
683da6c28aaSamw 		mutex_exit(&xa->xa_mutex);
684da6c28aaSamw 		smb_xa_close(xa);
685dc20a302Sas200622 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
686faa1795aSjb150015 		return (SDRC_ERROR);
687da6c28aaSamw 	}
688da6c28aaSamw 	if (MBC_SHADOW_CHAIN(&xa->req_data_mb, &sr->command, dsoff, dscnt)) {
689da6c28aaSamw 		mutex_exit(&xa->xa_mutex);
690da6c28aaSamw 		smb_xa_close(xa);
691dc20a302Sas200622 		smbsr_error(sr, 0, ERRDOS, ERRbadformat);
692faa1795aSjb150015 		return (SDRC_ERROR);
693da6c28aaSamw 	}
694da6c28aaSamw 	mutex_exit(&xa->xa_mutex);
695da6c28aaSamw 
696da6c28aaSamw 	if (!smb_trans_ready(xa))
697da6c28aaSamw 		return (SDRC_NO_REPLY);
698da6c28aaSamw 
699da6c28aaSamw 	if (!smb_xa_complete(xa))
700da6c28aaSamw 		return (SDRC_NO_REPLY);
701da6c28aaSamw 
702da6c28aaSamw 	return (smb_nt_trans_dispatch(sr, xa));
703da6c28aaSamw }
704da6c28aaSamw 
7057b59d02dSjb150015 static int
706da6c28aaSamw smb_trans_ready(struct smb_xa *xa)
707da6c28aaSamw {
708da6c28aaSamw 	int rc;
709da6c28aaSamw 
710da6c28aaSamw 	mutex_enter(&xa->xa_mutex);
711da6c28aaSamw 	rc = xa->req_disp_data >= xa->smb_tdscnt &&
712da6c28aaSamw 	    xa->req_disp_param >= xa->smb_tpscnt;
713da6c28aaSamw 	mutex_exit(&xa->xa_mutex);
714da6c28aaSamw 
715da6c28aaSamw 	return (rc);
716da6c28aaSamw }
717da6c28aaSamw 
718*3ad684d6Sjb150015 static void
719*3ad684d6Sjb150015 smb_encode_SHARE_INFO_1(struct mbuf_chain *output, struct mbuf_chain *text,
720*3ad684d6Sjb150015     char *oem_name, uint16_t type, char *comment)
721da6c28aaSamw {
722*3ad684d6Sjb150015 	(void) smb_encode_mbc(output, "13c.wl", oem_name,
723*3ad684d6Sjb150015 	    type, MBC_LENGTH(text));
724da6c28aaSamw 
725*3ad684d6Sjb150015 	(void) smb_encode_mbc(text, "s", comment ? comment : "");
7266537f381Sas200622 }
727da6c28aaSamw 
728*3ad684d6Sjb150015 static void
729*3ad684d6Sjb150015 smb_encode_SHARE_INFO_2(struct mbuf_chain *output, struct mbuf_chain *text,
730*3ad684d6Sjb150015 	smb_request_t *sr, char *oem_name, uint16_t type,
731*3ad684d6Sjb150015 	char *comment, uint16_t access, char *path, char *password)
732da6c28aaSamw {
733da6c28aaSamw 	unsigned char pword[9];
734da6c28aaSamw 
735da6c28aaSamw 	bzero(pword, sizeof (pword));
736da6c28aaSamw 	(void) strncpy((char *)pword, password, sizeof (pword));
737*3ad684d6Sjb150015 	smb_encode_SHARE_INFO_1(output, text, oem_name, type, comment);
738da6c28aaSamw 	(void) smb_encode_mbc(output, "wwwl9c.",
739da6c28aaSamw 	    access,
740faa1795aSjb150015 	    sr->sr_cfg->skc_maxconnections,
741faa1795aSjb150015 	    smb_server_get_session_count(),
742da6c28aaSamw 	    MBC_LENGTH(text),
743*3ad684d6Sjb150015 	    pword);
744da6c28aaSamw 	(void) smb_encode_mbc(text, "s", path);
745da6c28aaSamw }
746da6c28aaSamw 
747da6c28aaSamw int
748da6c28aaSamw smb_trans_net_share_enum(struct smb_request *sr, struct smb_xa *xa)
749da6c28aaSamw {
750faa1795aSjb150015 	door_handle_t dhdl = sr->sr_server->sv_lmshrd;
751da6c28aaSamw 
752da6c28aaSamw 	/*
753da6c28aaSamw 	 * Number of data bytes that will
754da6c28aaSamw 	 * be sent in the current response
755da6c28aaSamw 	 */
756da6c28aaSamw 	uint16_t data_scnt;
757da6c28aaSamw 
758da6c28aaSamw 	/*
759da6c28aaSamw 	 * Total number of data bytes that
760da6c28aaSamw 	 * are sent till now. This is only
761da6c28aaSamw 	 * used for calculating current data
762da6c28aaSamw 	 * displacement
763da6c28aaSamw 	 */
764da6c28aaSamw 	uint16_t tot_data_scnt;
765da6c28aaSamw 
766da6c28aaSamw 	/*
767da6c28aaSamw 	 * Number of parameter bytes should
768da6c28aaSamw 	 * be sent for the current response.
769da6c28aaSamw 	 * It is 8 for the 1st response and
770da6c28aaSamw 	 * 0 for others
771da6c28aaSamw 	 */
772da6c28aaSamw 	uint16_t param_scnt;
773da6c28aaSamw 
774da6c28aaSamw 	/* number of setup and parameter bytes */
775da6c28aaSamw 	uint16_t n_setup, n_param;
776da6c28aaSamw 
777da6c28aaSamw 	/* data and parameter displacement */
778da6c28aaSamw 	uint16_t data_disp, param_disp;
779da6c28aaSamw 
780da6c28aaSamw 	/* parameter and data offset and pad */
781da6c28aaSamw 	int param_off, param_pad, data_off, data_pad;
782da6c28aaSamw 
783da6c28aaSamw 	/*
784da6c28aaSamw 	 * total bytes of parameters and data
785da6c28aaSamw 	 * in the packet, plus the pad bytes.
786da6c28aaSamw 	 */
787da6c28aaSamw 	int tot_packet_bytes;
788da6c28aaSamw 
789*3ad684d6Sjb150015 	boolean_t first_resp;
790da6c28aaSamw 
791*3ad684d6Sjb150015 	char fmt[16];
792*3ad684d6Sjb150015 	struct mbuf_chain reply;
793*3ad684d6Sjb150015 
794*3ad684d6Sjb150015 	uint16_t level;
795*3ad684d6Sjb150015 	uint16_t pkt_bufsize;
796*3ad684d6Sjb150015 	smb_enumshare_info_t esi;
797*3ad684d6Sjb150015 	char *sent_buf;
798*3ad684d6Sjb150015 
799*3ad684d6Sjb150015 	ASSERT(sr->uid_user);
800da6c28aaSamw 
801da6c28aaSamw 	/*
802da6c28aaSamw 	 * Initialize the mbuf chain of reply to zero. If it is not
803da6c28aaSamw 	 * zero, code inside the while loop will try to free the chain.
804da6c28aaSamw 	 */
805da6c28aaSamw 	bzero(&reply, sizeof (struct mbuf_chain));
806da6c28aaSamw 
807*3ad684d6Sjb150015 	if (smb_decode_mbc(&xa->req_param_mb, "ww", &level,
808*3ad684d6Sjb150015 	    &esi.es_bufsize) != 0)
809faa1795aSjb150015 		return (SDRC_NOT_IMPLEMENTED);
810da6c28aaSamw 
811da6c28aaSamw 	if (level != 1) {
812*3ad684d6Sjb150015 		/*
813*3ad684d6Sjb150015 		 * Only level 1 is valid for NetShareEnum
814*3ad684d6Sjb150015 		 * None of the error codes in the spec are meaningful
815*3ad684d6Sjb150015 		 * here. This error code is returned by Windows.
816*3ad684d6Sjb150015 		 */
817da6c28aaSamw 		(void) smb_encode_mbc(&xa->rep_param_mb, "wwww",
818*3ad684d6Sjb150015 		    ERROR_INVALID_LEVEL, 0, 0, 0);
819faa1795aSjb150015 		return (SDRC_SUCCESS);
820da6c28aaSamw 	}
821da6c28aaSamw 
822*3ad684d6Sjb150015 	esi.es_buf = kmem_zalloc(esi.es_bufsize, KM_SLEEP);
823*3ad684d6Sjb150015 	esi.es_username = sr->uid_user->u_name;
824*3ad684d6Sjb150015 	(void) smb_kshare_enum(dhdl, &esi);
825da6c28aaSamw 
826*3ad684d6Sjb150015 	/* client buffer size is not big enough to hold any shares */
827*3ad684d6Sjb150015 	if (esi.es_nsent == 0) {
8287b59d02dSjb150015 		(void) smb_encode_mbc(&xa->rep_param_mb, "wwww",
829*3ad684d6Sjb150015 		    ERROR_MORE_DATA, 0, esi.es_nsent, esi.es_ntotal);
830*3ad684d6Sjb150015 		kmem_free(esi.es_buf, esi.es_bufsize);
831faa1795aSjb150015 		return (SDRC_SUCCESS);
832da6c28aaSamw 	}
833da6c28aaSamw 
834da6c28aaSamw 	/*
835da6c28aaSamw 	 * The rep_setup_mb is already initialized in smb_trans_dispatch().
836da6c28aaSamw 	 * Calling MBC_INIT() will initialized the structure and so the
837da6c28aaSamw 	 * pointer to the mbuf chains will be lost. Therefore, we need
838da6c28aaSamw 	 * to free the resources before calling MBC_INIT() again.
839da6c28aaSamw 	 */
840*3ad684d6Sjb150015 	n_setup = 0;	/* Setup count for NetShareEnum SMB is 0 */
841da6c28aaSamw 	m_freem(xa->rep_setup_mb.chain);
842da6c28aaSamw 	MBC_INIT(&xa->rep_setup_mb, n_setup * 2);
843da6c28aaSamw 
844*3ad684d6Sjb150015 	n_param = 8;
845*3ad684d6Sjb150015 	pkt_bufsize = sr->session->smb_msg_size -
846*3ad684d6Sjb150015 	    (SMB_HEADER_ED_LEN + RESP_HEADER_LEN + n_param);
847da6c28aaSamw 
848*3ad684d6Sjb150015 	tot_data_scnt = 0;
849*3ad684d6Sjb150015 	sent_buf = esi.es_buf;
850*3ad684d6Sjb150015 	first_resp = B_TRUE;
851*3ad684d6Sjb150015 
852*3ad684d6Sjb150015 	while (tot_data_scnt < esi.es_datasize) {
853*3ad684d6Sjb150015 		data_scnt = esi.es_datasize - tot_data_scnt;
854*3ad684d6Sjb150015 		if (data_scnt > pkt_bufsize)
855*3ad684d6Sjb150015 			data_scnt = pkt_bufsize;
856da6c28aaSamw 		m_freem(xa->rep_data_mb.chain);
857*3ad684d6Sjb150015 		MBC_INIT(&xa->rep_data_mb, data_scnt);
858*3ad684d6Sjb150015 
859*3ad684d6Sjb150015 		(void) sprintf(fmt, "%dc", data_scnt);
860*3ad684d6Sjb150015 		(void) smb_encode_mbc(&xa->rep_data_mb, fmt, sent_buf);
861*3ad684d6Sjb150015 
862*3ad684d6Sjb150015 		sent_buf += data_scnt;
863da6c28aaSamw 		tot_data_scnt += data_scnt;
864da6c28aaSamw 
865da6c28aaSamw 		/* Only the 1st response packet contains parameters */
866da6c28aaSamw 		param_scnt = (first_resp) ? n_param : 0;
867da6c28aaSamw 		param_pad = 1;				/* always one */
868da6c28aaSamw 		param_off = SMB_HEADER_ED_LEN + RESP_HEADER_LEN;
869da6c28aaSamw 		param_disp = (first_resp) ? 0 : n_param;
870da6c28aaSamw 
871da6c28aaSamw 		m_freem(xa->rep_param_mb.chain);
872da6c28aaSamw 		MBC_INIT(&xa->rep_param_mb, param_scnt);
873*3ad684d6Sjb150015 
874da6c28aaSamw 		if (first_resp) {
875*3ad684d6Sjb150015 			first_resp = B_FALSE;
876da6c28aaSamw 			(void) smb_encode_mbc(&xa->rep_param_mb, "wwww",
877*3ad684d6Sjb150015 			    (esi.es_ntotal > esi.es_nsent)
878*3ad684d6Sjb150015 			    ? ERROR_MORE_DATA : 0,
879*3ad684d6Sjb150015 			    0, esi.es_nsent, esi.es_ntotal);
880da6c28aaSamw 		}
881da6c28aaSamw 
882da6c28aaSamw 		data_pad = (param_off + n_param) & 1;	/* Pad to short */
883da6c28aaSamw 
884da6c28aaSamw 		/* data off from hdr start */
885da6c28aaSamw 		data_off = param_off + param_scnt + data_pad;
886da6c28aaSamw 		data_disp = tot_data_scnt - data_scnt;
887da6c28aaSamw 		tot_packet_bytes = param_pad + param_scnt + data_pad +
888da6c28aaSamw 		    data_scnt;
889da6c28aaSamw 
890da6c28aaSamw 		/*
891da6c28aaSamw 		 * Calling MBC_INIT() will initialized the structure and so the
892da6c28aaSamw 		 * pointer to the mbuf chains will be lost. Therefore, we need
893da6c28aaSamw 		 * to free the resources if any before calling MBC_INIT().
894da6c28aaSamw 		 */
895da6c28aaSamw 		m_freem(reply.chain);
896da6c28aaSamw 		MBC_INIT(&reply, SMB_HEADER_ED_LEN
897*3ad684d6Sjb150015 		    + sizeof (uint8_t)		/* word parameters count */
898*3ad684d6Sjb150015 		    + 10*sizeof (uint16_t)	/* word parameters */
899*3ad684d6Sjb150015 		    + n_setup*sizeof (uint16_t)	/* setup parameters */
900*3ad684d6Sjb150015 		    + sizeof (uint16_t)		/* total data byte count */
901da6c28aaSamw 		    + tot_packet_bytes);
902da6c28aaSamw 
903da6c28aaSamw 		(void) smb_encode_mbc(&reply, SMB_HEADER_ED_FMT,
904da6c28aaSamw 		    sr->first_smb_com,
905da6c28aaSamw 		    sr->smb_rcls,
906da6c28aaSamw 		    sr->smb_reh,
907da6c28aaSamw 		    sr->smb_err,
908da6c28aaSamw 		    sr->smb_flg | SMB_FLAGS_REPLY,
909da6c28aaSamw 		    sr->smb_flg2,
910da6c28aaSamw 		    sr->smb_pid_high,
911da6c28aaSamw 		    sr->smb_sig,
912da6c28aaSamw 		    sr->smb_tid,
913da6c28aaSamw 		    sr->smb_pid,
914da6c28aaSamw 		    sr->smb_uid,
915da6c28aaSamw 		    sr->smb_mid);
916da6c28aaSamw 
917da6c28aaSamw 		(void) smb_encode_mbc(&reply,
918da6c28aaSamw 		    "b ww 2. www www b . C w #. C #. C",
919da6c28aaSamw 		    10 + n_setup,	/* wct */
920da6c28aaSamw 		    n_param,		/* Total Parameter Bytes */
921*3ad684d6Sjb150015 		    esi.es_datasize,	/* Total Data Bytes */
922da6c28aaSamw 		    param_scnt,		/* Total Parameter Bytes this buffer */
923da6c28aaSamw 		    param_off,		/* Param offset from header start */
924da6c28aaSamw 		    param_disp,		/* Param displacement */
925da6c28aaSamw 		    data_scnt,		/* Total Data Bytes this buffer */
926da6c28aaSamw 		    data_off,		/* Data offset from header start */
927da6c28aaSamw 		    data_disp,		/* Data displacement */
928da6c28aaSamw 		    n_setup,		/* suwcnt */
929da6c28aaSamw 		    &xa->rep_setup_mb, 	/* setup[] */
930da6c28aaSamw 		    tot_packet_bytes,	/* Total data bytes */
931da6c28aaSamw 		    param_pad,
932da6c28aaSamw 		    &xa->rep_param_mb,
933da6c28aaSamw 		    data_pad,
934da6c28aaSamw 		    &xa->rep_data_mb);
935da6c28aaSamw 
936da6c28aaSamw 		if (sr->session->signing.flags & SMB_SIGNING_ENABLED)
937da6c28aaSamw 			smb_sign_reply(sr, NULL);
938da6c28aaSamw 
939da6c28aaSamw 		(void) smb_session_send(sr->session, 0, &reply);
940da6c28aaSamw 	}
941da6c28aaSamw 
942*3ad684d6Sjb150015 	kmem_free(esi.es_buf, esi.es_bufsize);
943da6c28aaSamw 	return (SDRC_NO_REPLY);
944da6c28aaSamw }
945da6c28aaSamw 
946da6c28aaSamw int
947*3ad684d6Sjb150015 smb_trans_net_share_getinfo(smb_request_t *sr, struct smb_xa *xa)
948da6c28aaSamw {
949*3ad684d6Sjb150015 	uint16_t		level, max_bytes, access;
950da6c28aaSamw 	struct mbuf_chain	str_mb;
951da6c28aaSamw 	char			*share;
952da6c28aaSamw 	char			*password;
953da6c28aaSamw 	lmshare_info_t		si;
954*3ad684d6Sjb150015 	int			rc;
955da6c28aaSamw 
956*3ad684d6Sjb150015 	if (smb_decode_mbc(&xa->req_param_mb, "%sww", sr,
957*3ad684d6Sjb150015 	    &share, &level, &max_bytes) != 0)
958faa1795aSjb150015 		return (SDRC_NOT_IMPLEMENTED);
959da6c28aaSamw 
960da6c28aaSamw 	(void) utf8_strlwr(share);
961*3ad684d6Sjb150015 	rc = smb_kshare_getinfo(sr->sr_server->sv_lmshrd, share, &si);
962*3ad684d6Sjb150015 	if ((rc != NERR_Success) || (si.mode & LMSHRM_LONGNAME)) {
963da6c28aaSamw 		(void) smb_encode_mbc(&xa->rep_param_mb, "www",
964da6c28aaSamw 		    NERR_NetNameNotFound, 0, 0);
965faa1795aSjb150015 		return (SDRC_SUCCESS);
966da6c28aaSamw 	}
967da6c28aaSamw 
968*3ad684d6Sjb150015 	access = SHARE_ACCESS_ALL;
969da6c28aaSamw 	password = "";
970da6c28aaSamw 
971da6c28aaSamw 	MBC_INIT(&str_mb, max_bytes);
972da6c28aaSamw 
973da6c28aaSamw 	switch (level) {
974da6c28aaSamw 	case 0 :
975*3ad684d6Sjb150015 		(void) smb_encode_mbc(&xa->rep_data_mb, "13c", si.oem_name);
976da6c28aaSamw 		break;
977da6c28aaSamw 
978da6c28aaSamw 	case 1 :
979*3ad684d6Sjb150015 		smb_encode_SHARE_INFO_1(&xa->rep_data_mb, &str_mb,
980*3ad684d6Sjb150015 		    si.oem_name, si.stype, si.comment);
981da6c28aaSamw 		break;
982da6c28aaSamw 
983da6c28aaSamw 	case 2 :
984*3ad684d6Sjb150015 		smb_encode_SHARE_INFO_2(&xa->rep_data_mb, &str_mb, sr,
985*3ad684d6Sjb150015 		    si.oem_name, si.stype, si.comment, access, si.directory,
986*3ad684d6Sjb150015 		    password);
987*3ad684d6Sjb150015 		break;
988*3ad684d6Sjb150015 
989da6c28aaSamw 	default:
990*3ad684d6Sjb150015 		(void) smb_encode_mbc(&xa->rep_param_mb, "www",
991*3ad684d6Sjb150015 		    ERROR_INVALID_LEVEL, 0, 0);
992da6c28aaSamw 		m_freem(str_mb.chain);
993faa1795aSjb150015 		return (SDRC_NOT_IMPLEMENTED);
994da6c28aaSamw 	}
995da6c28aaSamw 
996*3ad684d6Sjb150015 	(void) smb_encode_mbc(&xa->rep_param_mb, "www", NERR_Success,
997da6c28aaSamw 	    -MBC_LENGTH(&xa->rep_data_mb),
998da6c28aaSamw 	    MBC_LENGTH(&xa->rep_data_mb) + MBC_LENGTH(&str_mb));
999da6c28aaSamw 	(void) smb_encode_mbc(&xa->rep_data_mb, "C", &str_mb);
1000da6c28aaSamw 	m_freem(str_mb.chain);
1001faa1795aSjb150015 	return (SDRC_SUCCESS);
1002da6c28aaSamw }
1003da6c28aaSamw 
1004da6c28aaSamw int
1005*3ad684d6Sjb150015 smb_trans_net_workstation_getinfo(struct smb_request *sr, struct smb_xa *xa)
1006da6c28aaSamw {
1007*3ad684d6Sjb150015 	uint16_t		level, max_bytes;
1008da6c28aaSamw 	struct mbuf_chain	str_mb;
1009da6c28aaSamw 	char *domain;
1010da6c28aaSamw 	char *hostname;
1011da6c28aaSamw 
1012*3ad684d6Sjb150015 	if ((smb_decode_mbc(&xa->req_param_mb, "ww",
1013*3ad684d6Sjb150015 	    &level, &max_bytes) != 0) ||
1014da6c28aaSamw 	    (level != 10)) {
1015da6c28aaSamw 		(void) smb_encode_mbc(&xa->rep_param_mb, "wwww",
1016da6c28aaSamw 		    NERR_BadTransactConfig, 0, 0, 0);
1017faa1795aSjb150015 		return (SDRC_SUCCESS);
1018da6c28aaSamw 	}
1019da6c28aaSamw 
1020faa1795aSjb150015 	domain = sr->sr_cfg->skc_resource_domain;
1021faa1795aSjb150015 	hostname = sr->sr_cfg->skc_hostname;
1022da6c28aaSamw 
1023da6c28aaSamw 	MBC_INIT(&str_mb, max_bytes);
1024da6c28aaSamw 
1025da6c28aaSamw 	(void) smb_encode_mbc(&str_mb, "."); /* Prevent NULL pointers */
1026da6c28aaSamw 
1027da6c28aaSamw 	(void) smb_encode_mbc(&xa->rep_data_mb, "l", MBC_LENGTH(&str_mb));
1028da6c28aaSamw 	(void) smb_encode_mbc(&str_mb, "s", hostname);
1029da6c28aaSamw 	(void) smb_encode_mbc(&xa->rep_data_mb, "l", MBC_LENGTH(&str_mb));
1030da6c28aaSamw 	(void) smb_encode_mbc(&str_mb, "s", "nobody");
1031da6c28aaSamw 	(void) smb_encode_mbc(&xa->rep_data_mb, "l", MBC_LENGTH(&str_mb));
1032da6c28aaSamw 	(void) smb_encode_mbc(&str_mb, "s", domain);
1033da6c28aaSamw 	(void) smb_encode_mbc(&xa->rep_data_mb, "bbl",
1034da6c28aaSamw 	    SMB_VERSION_MAJOR, SMB_VERSION_MINOR, MBC_LENGTH(&str_mb));
1035da6c28aaSamw 	(void) smb_encode_mbc(&str_mb, "s", domain);
1036da6c28aaSamw 	(void) smb_encode_mbc(&xa->rep_data_mb, "l", MBC_LENGTH(&str_mb));
1037da6c28aaSamw 	(void) smb_encode_mbc(&str_mb, "s", domain);
1038da6c28aaSamw 
1039da6c28aaSamw 	(void) smb_encode_mbc(&xa->rep_param_mb, "www", 0,
1040da6c28aaSamw 	    -MBC_LENGTH(&xa->rep_data_mb),
1041da6c28aaSamw 	    MBC_LENGTH(&xa->rep_data_mb) + MBC_LENGTH(&str_mb));
1042da6c28aaSamw 	(void) smb_encode_mbc(&xa->rep_data_mb, "C", &str_mb);
1043da6c28aaSamw 	m_freem(str_mb.chain);
1044faa1795aSjb150015 	return (SDRC_SUCCESS);
1045da6c28aaSamw }
1046da6c28aaSamw 
1047da6c28aaSamw int
1048*3ad684d6Sjb150015 smb_trans_net_user_getinfo(struct smb_request *sr, struct smb_xa *xa)
1049da6c28aaSamw {
1050*3ad684d6Sjb150015 	uint16_t		level, max_bytes;
1051da6c28aaSamw 	unsigned char		*user;
1052da6c28aaSamw 	int rc;
1053da6c28aaSamw 
1054*3ad684d6Sjb150015 	rc = smb_decode_mbc(&xa->req_param_mb, "%sww", sr,
1055da6c28aaSamw 	    &user,
1056da6c28aaSamw 	    &level,
1057da6c28aaSamw 	    &max_bytes);
1058da6c28aaSamw 
1059da6c28aaSamw 	if (rc != 0)
1060faa1795aSjb150015 		return (SDRC_NOT_IMPLEMENTED);
1061da6c28aaSamw 
1062da6c28aaSamw 	(void) smb_encode_mbc(&xa->rep_param_mb, "www",
1063da6c28aaSamw 	    NERR_UserNotFound, 0, 0);
1064faa1795aSjb150015 	return (SDRC_SUCCESS);
1065da6c28aaSamw }
1066da6c28aaSamw 
10677b59d02dSjb150015 smb_sdrc_t
1068*3ad684d6Sjb150015 smb_trans_net_server_getinfo(struct smb_request *sr, struct smb_xa *xa)
1069da6c28aaSamw {
1070*3ad684d6Sjb150015 	uint16_t		level, buf_size;
1071*3ad684d6Sjb150015 	uint16_t		avail_data, max_data;
1072da6c28aaSamw 	char			server_name[16];
1073da6c28aaSamw 	struct mbuf_chain	str_mb;
1074da6c28aaSamw 
1075*3ad684d6Sjb150015 	if (smb_decode_mbc(&xa->req_param_mb, "ww", &level, &buf_size) != 0)
1076faa1795aSjb150015 		return (SDRC_ERROR);
1077da6c28aaSamw 
1078*3ad684d6Sjb150015 	max_data = MBC_MAXBYTES(&xa->rep_data_mb);
1079da6c28aaSamw 
1080da6c28aaSamw 	MBC_INIT(&str_mb, buf_size);
1081da6c28aaSamw 
1082da6c28aaSamw 	bzero(server_name, sizeof (server_name));
1083*3ad684d6Sjb150015 	(void) strncpy(server_name, sr->sr_cfg->skc_hostname,
1084*3ad684d6Sjb150015 	    sizeof (server_name));
1085da6c28aaSamw 
1086*3ad684d6Sjb150015 	/* valid levels are 0 and 1 */
1087da6c28aaSamw 	switch (level) {
1088da6c28aaSamw 	case 0:
1089da6c28aaSamw 		(void) smb_encode_mbc(&xa->rep_data_mb, "16c", server_name);
1090da6c28aaSamw 		break;
1091*3ad684d6Sjb150015 
1092da6c28aaSamw 	case 1:
1093*3ad684d6Sjb150015 		(void) smb_encode_mbc(&str_mb, "s",
1094*3ad684d6Sjb150015 		    sr->sr_cfg->skc_system_comment);
1095da6c28aaSamw 		(void) smb_encode_mbc(&xa->rep_data_mb, "16cbbll", server_name,
1096da6c28aaSamw 		    SMB_VERSION_MAJOR, SMB_VERSION_MINOR,
1097*3ad684d6Sjb150015 		    MY_SERVER_TYPE, max_data - MBC_LENGTH(&str_mb));
1098da6c28aaSamw 		break;
1099*3ad684d6Sjb150015 
1100da6c28aaSamw 	default:
1101*3ad684d6Sjb150015 		(void) smb_encode_mbc(&xa->rep_param_mb, "www",
1102*3ad684d6Sjb150015 		    ERROR_INVALID_LEVEL, 0, 0);
1103da6c28aaSamw 		m_freem(str_mb.chain);
1104*3ad684d6Sjb150015 		return (SDRC_SUCCESS);
1105da6c28aaSamw 	}
1106da6c28aaSamw 
1107*3ad684d6Sjb150015 	avail_data = MBC_LENGTH(&xa->rep_data_mb) + MBC_LENGTH(&str_mb);
1108*3ad684d6Sjb150015 	(void) smb_encode_mbc(&xa->rep_param_mb, "www",
1109*3ad684d6Sjb150015 	    NERR_Success, max_data - avail_data, avail_data);
1110da6c28aaSamw 	(void) smb_encode_mbc(&xa->rep_data_mb, "C", &str_mb);
1111da6c28aaSamw 	m_freem(str_mb.chain);
1112faa1795aSjb150015 	return (SDRC_SUCCESS);
1113da6c28aaSamw }
1114da6c28aaSamw 
1115da6c28aaSamw /*
1116da6c28aaSamw  * 6.4 The NetServerEnum2 RAP Service
1117da6c28aaSamw  *
1118da6c28aaSamw  * The NetServerEnum2 RAP service lists all computers of the specified type
1119da6c28aaSamw  * or types that are visible in the specified domains. It may also
1120da6c28aaSamw  * enumerate domains.
1121da6c28aaSamw  *
1122da6c28aaSamw  * The following definition uses the notation and terminology defined in
1123da6c28aaSamw  * the CIFS Remote Administration Protocol specification, which is required
1124da6c28aaSamw  * in order to make it well-defined. The definition is:
1125da6c28aaSamw  *
1126da6c28aaSamw  *     uint16_t NetServerEnum2 (
1127da6c28aaSamw  *         uint16_t  sLevel,
1128da6c28aaSamw  *         RCVBUF          pbBuffer,
1129da6c28aaSamw  *         RCVBUFLEN       cbBuffer,
1130da6c28aaSamw  *         ENTCOUNT        pcEntriesRead,
1131da6c28aaSamw  *         uint16_t  *pcTotalAvail,
1132da6c28aaSamw  *         uint32_t   fServerType,
1133da6c28aaSamw  *         char            *pszDomain,
1134da6c28aaSamw  *     );
1135da6c28aaSamw  *
1136da6c28aaSamw  * where:
1137da6c28aaSamw  *
1138da6c28aaSamw  *    sLevel specifies the level of detail (0 or 1) requested.
1139da6c28aaSamw  *
1140da6c28aaSamw  *    pbBuffer points to the buffer to receive the returned data. If the
1141da6c28aaSamw  *    function is successful, the buffer contains a sequence of
1142da6c28aaSamw  *    server_info_x structures, where x is 0 or 1, depending on the
1143da6c28aaSamw  *    level of detail requested.
1144da6c28aaSamw  *
1145da6c28aaSamw  *    cbBuffer specifies the size, in bytes, of the buffer pointed to by
1146da6c28aaSamw  *    the pbBuffer parameter.
1147da6c28aaSamw  *
1148da6c28aaSamw  *    pcEntriesRead points to a 16 bit variable that receives a count of
1149da6c28aaSamw  *    the number of servers enumerated in the buffer. This count is
1150da6c28aaSamw  *    valid only if NetServerEnum2 returns the NERR_Success or
1151da6c28aaSamw  *    ERROR_MORE_DATA values.
1152da6c28aaSamw  *
1153da6c28aaSamw  *    pcTotal Avail points to a 16 bit variable that receives a count of
1154da6c28aaSamw  *    the total number of available entries. This count is valid only if
1155da6c28aaSamw  *    NetServerEnum2 returns the NERR_Success or ERROR_MORE_DATA values.
1156da6c28aaSamw  *
1157da6c28aaSamw  *     fServerType specifies the type or types of computers to enumerate.
1158da6c28aaSamw  *     Computers that match at least one of the specified types are
1159da6c28aaSamw  *     returned in the buffer. Possible values are defined in the request
1160da6c28aaSamw  *     parameters section.
1161da6c28aaSamw  *
1162da6c28aaSamw  *    pszDomain points to a null-terminated string that contains the
1163da6c28aaSamw  *    name of the workgroup in which to enumerate computers of the
1164da6c28aaSamw  *    specified type or types. If the pszDomain parameter is a null
1165da6c28aaSamw  *    string or a null pointer, servers are enumerated for the current
1166da6c28aaSamw  *    domain of the computer.
1167da6c28aaSamw  *
1168da6c28aaSamw  * 6.4.1 Transaction Request Parameters section
1169da6c28aaSamw  *
1170da6c28aaSamw  * The Transaction request parameters section in this instance contains:
1171da6c28aaSamw  * . The 16 bit function number for NetServerEnum2 which is 104.
1172da6c28aaSamw  * . The parameter descriptor string which is "WrLehDz".
1173da6c28aaSamw  * . The data descriptor string for the (returned) data which is "B16" for
1174da6c28aaSamw  *   level detail 0 or "B16BBDz" for level detail 1.
1175da6c28aaSamw  * . The actual parameters as described by the parameter descriptor
1176da6c28aaSamw  *   string.
1177da6c28aaSamw  *
1178da6c28aaSamw  * The parameters are:
1179da6c28aaSamw  * . A 16 bit integer with a value of 0 or 1 (corresponding to the "W" in
1180da6c28aaSamw  *   the parameter descriptor string. This represents the level of detail
1181da6c28aaSamw  *   the server is expected to return
1182da6c28aaSamw  * . A 16 bit integer that contains the size of the receive buffer.
1183da6c28aaSamw  * . A 32 bit integer that represents the type of servers the function
1184da6c28aaSamw  *   should enumerate. The possible values may be any of the following or
1185da6c28aaSamw  *   a combination of the following:
1186da6c28aaSamw  *
1187da6c28aaSamw  * SV_TYPE_WORKSTATION        0x00000001 All workstations
1188da6c28aaSamw  * SV_TYPE_SERVER             0x00000002 All servers
1189da6c28aaSamw  * SV_TYPE_SQLSERVER          0x00000004 Any server running with SQL
1190da6c28aaSamw  *                                       server
1191da6c28aaSamw  * SV_TYPE_DOMAIN_CTRL        0x00000008 Primary domain controller
1192da6c28aaSamw  * SV_TYPE_DOMAIN_BAKCTRL     0x00000010 Backup domain controller
1193da6c28aaSamw  * SV_TYPE_TIME_SOURCE        0x00000020 Server running the timesource
1194da6c28aaSamw  *                                       service
1195da6c28aaSamw  * SV_TYPE_AFP                0x00000040 Apple File Protocol servers
1196da6c28aaSamw  * SV_TYPE_NOVELL             0x00000080 Novell servers
1197da6c28aaSamw  * SV_TYPE_DOMAIN_MEMBER      0x00000100 Domain Member
1198da6c28aaSamw  * SV_TYPE_PRINTQ_SERVER      0x00000200 Server sharing print queue
1199da6c28aaSamw  * SV_TYPE_DIALIN_SERVER      0x00000400 Server running dialin service.
1200da6c28aaSamw  * SV_TYPE_XENIX_SERVER       0x00000800 Xenix server
1201da6c28aaSamw  * SV_TYPE_NT                 0x00001000 NT server
1202da6c28aaSamw  * SV_TYPE_WFW                0x00002000 Server running Windows for
1203da6c28aaSamw  *                                       Workgroups
1204da6c28aaSamw  * SV_TYPE_SERVER_NT          0x00008000 Windows NT non DC server
1205da6c28aaSamw  * SV_TYPE_POTENTIAL_BROWSER  0x00010000 Server that can run the browser
1206da6c28aaSamw  *                                       service
1207da6c28aaSamw  * SV_TYPE_BACKUP_BROWSER     0x00020000 Backup browser server
1208da6c28aaSamw  * SV_TYPE_MASTER_BROWSER     0x00040000 Master browser server
1209da6c28aaSamw  * SV_TYPE_DOMAIN_MASTER      0x00080000 Domain Master Browser server
1210da6c28aaSamw  * SV_TYPE_LOCAL_LIST_ONLY    0x40000000 Enumerate only entries marked
1211da6c28aaSamw  *                                       "local"
1212da6c28aaSamw  * SV_TYPE_DOMAIN_ENUM        0x80000000 Enumerate Domains. The pszDomain
1213da6c28aaSamw  *                                       parameter must be NULL.
1214da6c28aaSamw  *
1215da6c28aaSamw  * . A null terminated ASCII string representing the pszDomain parameter
1216da6c28aaSamw  *   described above
1217da6c28aaSamw  *
1218da6c28aaSamw  * 6.4.2 Transaction Request Data section
1219da6c28aaSamw  *
1220da6c28aaSamw  * There is no data or auxiliary data to send as part of the request.
1221da6c28aaSamw  *
1222da6c28aaSamw  * 6.4.3 Transaction Response Parameters section
1223da6c28aaSamw  *
1224da6c28aaSamw  * The transaction response parameters section consists of:
1225da6c28aaSamw  * . A 16 bit word indicating the return status. The possible values are:
1226da6c28aaSamw  *
1227da6c28aaSamw  * Code                   Value  Description
1228da6c28aaSamw  * NERR_Success           0      No errors encountered
1229da6c28aaSamw  * ERROR_MORE_DATA        234    Additional data is available
1230da6c28aaSamw  * NERR_ServerNotStarted  2114   The RAP service on the remote computer
1231da6c28aaSamw  *                               is not running
1232da6c28aaSamw  * NERR_BadTransactConfig 2141   The server is not configured for
1233da6c28aaSamw  *                               transactions, IPC$ is not shared
1234da6c28aaSamw  *
1235da6c28aaSamw  * . A 16 bit "converter" word.
1236da6c28aaSamw  * . A 16 bit number representing the number of entries returned.
1237da6c28aaSamw  * . A 16 bit number representing the total number of available entries.
1238da6c28aaSamw  *   If the supplied buffer is large enough, this will equal the number of
1239da6c28aaSamw  *   entries returned.
1240da6c28aaSamw  *
1241da6c28aaSamw  * 6.4.4 Transaction Response Data section
1242da6c28aaSamw  *
1243da6c28aaSamw  * The return data section consists of a number of SERVER_INFO_1 structures.
1244da6c28aaSamw  * The number of such structures present is determined by the third entry
1245da6c28aaSamw  * (described above) in the return parameters section.
1246da6c28aaSamw  *
1247da6c28aaSamw  * At level detail 0, the Transaction response data section contains a
1248da6c28aaSamw  * number of SERVER_INFO_0 data structure. The number of such structures is
1249da6c28aaSamw  * equal to the 16 bit number returned by the server in the third parameter
1250da6c28aaSamw  * in the Transaction response parameter section. The SERVER_INFO_0 data
1251da6c28aaSamw  * structure is defined as:
1252da6c28aaSamw  *
1253da6c28aaSamw  *     struct SERVER_INFO_0 {
1254da6c28aaSamw  *         char        sv0_name[16];
1255da6c28aaSamw  *     };
1256da6c28aaSamw  *
1257da6c28aaSamw  *  where:
1258da6c28aaSamw  *
1259da6c28aaSamw  *    sv0_name is a null-terminated string that specifies the name of a
1260da6c28aaSamw  *    computer or domain .
1261da6c28aaSamw  *
1262da6c28aaSamw  * At level detail 1, the Transaction response data section contains a
1263da6c28aaSamw  * number of SERVER_INFO_1 data structure. The number of such structures is
1264da6c28aaSamw  * equal to the 16 bit number returned by the server in the third parameter
1265da6c28aaSamw  * in the Transaction response parameter section. The SERVER_INFO_1 data
1266da6c28aaSamw  * structure is defined as:
1267da6c28aaSamw  *
1268da6c28aaSamw  *     struct SERVER_INFO_1 {
1269da6c28aaSamw  *         char            sv1_name[16];
1270da6c28aaSamw  *         char            sv1_version_major;
1271da6c28aaSamw  *         char            sv1_version_minor;
1272da6c28aaSamw  *         uint32_t   sv1_type;
1273da6c28aaSamw  *         char        *sv1_comment_or_master_browser;
1274da6c28aaSamw  *     };
1275da6c28aaSamw  *
1276da6c28aaSamw  *    sv1_name contains a null-terminated string that specifies the name
1277da6c28aaSamw  *    of a computer, or a domain name if SV_TYPE_DOMAIN_ENUM is set in
1278da6c28aaSamw  *    sv1_type.
1279da6c28aaSamw  *
1280da6c28aaSamw  *    sv1_version_major whatever was specified in the HostAnnouncement
1281da6c28aaSamw  *    or DomainAnnouncement frame with which the entry was registered.
1282da6c28aaSamw  *
1283da6c28aaSamw  *    sv1_version_minor whatever was specified in the HostAnnouncement
1284da6c28aaSamw  *    or DomainAnnouncement frame with which the entry was registered.
1285da6c28aaSamw  *
1286da6c28aaSamw  *    sv1_type specifies the type of software the computer is running.
1287da6c28aaSamw  *    The member can be one or a combination of the values defined above
1288da6c28aaSamw  *    in the Transaction request parameters section for fServerType.
1289da6c28aaSamw  *
1290da6c28aaSamw  *
1291da6c28aaSamw  *    sv1_comment_or_master_browser points to a null-terminated string. If
1292da6c28aaSamw  *    the sv1_type indicates that the entry is for a domain, this
1293da6c28aaSamw  *    specifies the name of server running the domain master browser;
1294da6c28aaSamw  *    otherwise, it specifies a comment describing the server. The comment
1295da6c28aaSamw  *    can be a null string or the pointer may be a null pointer.
1296da6c28aaSamw  *
1297da6c28aaSamw  *    In case there are multiple SERVER_INFO_1 data structures to
1298da6c28aaSamw  *    return, the server may put all these fixed length structures in
1299da6c28aaSamw  *    the return buffer, leave some space and then put all the variable
1300da6c28aaSamw  *    length data (the actual value of the sv1_comment strings) at the
1301da6c28aaSamw  *    end of the buffer.
1302da6c28aaSamw  *
1303da6c28aaSamw  * There is no auxiliary data to receive.
1304da6c28aaSamw  */
1305da6c28aaSamw 
1306da6c28aaSamw int
1307da6c28aaSamw smb_trans_net_server_enum2(struct smb_request *sr, struct smb_xa *xa)
1308da6c28aaSamw {
1309da6c28aaSamw 	uint16_t opcode, level, max_bytes;
1310da6c28aaSamw 	uint32_t server_type;
1311da6c28aaSamw 	unsigned char *domain;
1312da6c28aaSamw 	struct mbuf_chain str_mb;
1313da6c28aaSamw 	char *hostname, *s;
1314da6c28aaSamw 	smb_kmod_cfg_t *si;
1315da6c28aaSamw 
1316da6c28aaSamw 	if (smb_decode_mbc(&xa->req_param_mb,
1317da6c28aaSamw 	    "%w s(request format) s(reply format) wwls", sr, &opcode, &s, &s,
1318da6c28aaSamw 	    &level, &max_bytes, &server_type, &domain) != 0)
1319faa1795aSjb150015 		return (SDRC_NOT_IMPLEMENTED);
1320da6c28aaSamw 
1321faa1795aSjb150015 	si = sr->sr_cfg;
1322da6c28aaSamw 
1323da6c28aaSamw 	if (utf8_strcasecmp(si->skc_resource_domain, (char *)domain) != 0) {
1324da6c28aaSamw 		(void) smb_encode_mbc(&xa->rep_param_mb, "wwww", 0, 0, 0, 0);
1325faa1795aSjb150015 		return (SDRC_SUCCESS);
1326da6c28aaSamw 	}
1327da6c28aaSamw 
1328da6c28aaSamw 	if ((server_type & MY_SERVER_TYPE) == 0) {
1329da6c28aaSamw 		(void) smb_encode_mbc(&xa->rep_param_mb, "wwww", 0, 0, 0, 0);
1330faa1795aSjb150015 		return (SDRC_SUCCESS);
1331da6c28aaSamw 	}
1332da6c28aaSamw 
1333da6c28aaSamw 	MBC_INIT(&str_mb, max_bytes);
1334da6c28aaSamw 
1335da6c28aaSamw 	hostname = si->skc_hostname;
1336da6c28aaSamw 
1337da6c28aaSamw 	(void) smb_encode_mbc(&xa->rep_data_mb, "16c", hostname);
1338da6c28aaSamw 	if (level == 1) {
1339da6c28aaSamw 		(void) smb_encode_mbc(&xa->rep_data_mb, "bbll",
1340da6c28aaSamw 		    SMB_VERSION_MAJOR, SMB_VERSION_MINOR,
1341da6c28aaSamw 		    MY_SERVER_TYPE, MBC_LENGTH(&str_mb));
1342da6c28aaSamw 		(void) smb_encode_mbc(&str_mb, "s", si->skc_system_comment);
1343da6c28aaSamw 	}
1344da6c28aaSamw 
1345da6c28aaSamw 	(void) smb_encode_mbc(&xa->rep_param_mb, "wwww", 0,
1346da6c28aaSamw 	    -MBC_LENGTH(&xa->rep_data_mb), 1, 1);
1347da6c28aaSamw 	(void) smb_encode_mbc(&xa->rep_data_mb, "m", str_mb.chain);
1348faa1795aSjb150015 	return (SDRC_SUCCESS);
1349da6c28aaSamw }
1350da6c28aaSamw 
1351da6c28aaSamw /*
1352da6c28aaSamw  * is_supported_pipe
1353da6c28aaSamw  *
1354da6c28aaSamw  * Currently, just return 0 if the pipe is \\PIPE\repl otherwise
1355da6c28aaSamw  * return 1.
1356da6c28aaSamw  */
1357da6c28aaSamw int
1358da6c28aaSamw is_supported_pipe(char *pname)
1359da6c28aaSamw {
1360da6c28aaSamw 	if (utf8_strcasecmp(pname, PIPE_REPL) == 0)
1361da6c28aaSamw 		return (0);
1362da6c28aaSamw 
1363da6c28aaSamw 	return (1);
1364da6c28aaSamw }
1365da6c28aaSamw 
13667b59d02dSjb150015 static smb_sdrc_t
1367da6c28aaSamw smb_trans_dispatch(struct smb_request *sr, struct smb_xa *xa)
1368da6c28aaSamw {
1369da6c28aaSamw 	int		rc, pos;
1370da6c28aaSamw 	int		total_bytes, n_setup, n_param, n_data;
1371da6c28aaSamw 	int		param_off, param_pad, data_off, data_pad;
1372da6c28aaSamw 	uint16_t	opcode;
1373da6c28aaSamw 	uint16_t	devstate;
1374da6c28aaSamw 	char		*req_fmt;
1375da6c28aaSamw 	char		*rep_fmt;
1376da6c28aaSamw 	struct vardata_block vdb;
1377da6c28aaSamw 
1378da6c28aaSamw 	n_setup = (xa->smb_msrcnt < 200) ? xa->smb_msrcnt : 200;
1379da6c28aaSamw 	n_setup++;
1380da6c28aaSamw 	n_setup = n_setup & ~0x0001;
1381da6c28aaSamw 	n_param = (xa->smb_mprcnt < smb_maxbufsize)
1382da6c28aaSamw 	    ? xa->smb_mprcnt : smb_maxbufsize;
1383da6c28aaSamw 	n_param++;
1384da6c28aaSamw 	n_param = n_param & ~0x0001;
1385da6c28aaSamw 	rc = smb_maxbufsize - (SMBHEADERSIZE + 28 + n_setup + n_param);
1386da6c28aaSamw 	n_data =  (xa->smb_mdrcnt < rc) ? xa->smb_mdrcnt : rc;
1387da6c28aaSamw 	MBC_INIT(&xa->rep_setup_mb, n_setup * 2);
1388da6c28aaSamw 	MBC_INIT(&xa->rep_param_mb, n_param);
1389da6c28aaSamw 	MBC_INIT(&xa->rep_data_mb, n_data);
1390da6c28aaSamw 
1391da6c28aaSamw 	if (xa->smb_suwcnt > 0 && STYPE_ISIPC(sr->tid_tree->t_res_type)) {
1392da6c28aaSamw 		rc = smb_decode_mbc(&xa->req_setup_mb, "ww", &opcode,
1393da6c28aaSamw 		    &sr->smb_fid);
1394da6c28aaSamw 		if (rc != 0)
1395da6c28aaSamw 			goto trans_err_not_supported;
1396da6c28aaSamw 		switch (opcode) {
1397da6c28aaSamw 		case TRANS_SET_NMPIPE_STATE:
1398da6c28aaSamw 			if ((rc = smb_decode_mbc(&xa->req_param_mb, "w",
1399da6c28aaSamw 			    &devstate)) != 0)
1400da6c28aaSamw 				goto trans_err_not_supported;
1401da6c28aaSamw 
1402faa1795aSjb150015 			rc = SDRC_SUCCESS;
1403da6c28aaSamw 			break;
1404da6c28aaSamw 
1405da6c28aaSamw 		case TRANS_TRANSACT_NMPIPE:
1406da6c28aaSamw 			sr->fid_ofile = smb_ofile_lookup_by_fid(sr->tid_tree,
1407da6c28aaSamw 			    sr->smb_fid);
1408da6c28aaSamw 			if (sr->fid_ofile == NULL) {
1409dc20a302Sas200622 				smbsr_error(sr, NT_STATUS_INVALID_HANDLE,
1410da6c28aaSamw 				    ERRDOS, ERRbadfid);
1411faa1795aSjb150015 				return (SDRC_ERROR);
1412da6c28aaSamw 			}
1413da6c28aaSamw 
1414da6c28aaSamw 			rc = smb_decode_mbc(&xa->req_data_mb, "#B",
1415da6c28aaSamw 			    xa->smb_tdscnt, &vdb);
1416da6c28aaSamw 			if (rc != 0)
1417da6c28aaSamw 				goto trans_err_not_supported;
1418da6c28aaSamw 
1419da6c28aaSamw 			rc = smb_rpc_transact(sr, &vdb.uio);
1420da6c28aaSamw 			break;
1421da6c28aaSamw 
1422da6c28aaSamw 		case TRANS_WAIT_NMPIPE:
1423da6c28aaSamw 			if (is_supported_pipe(xa->xa_smb_trans_name) == 0) {
1424dc20a302Sas200622 				smbsr_error(sr, 0, ERRDOS, ERRbadfile);
1425faa1795aSjb150015 				return (SDRC_ERROR);
1426da6c28aaSamw 			}
1427faa1795aSjb150015 			rc = SDRC_SUCCESS;
1428da6c28aaSamw 			break;
1429da6c28aaSamw 
1430da6c28aaSamw 		default:
1431da6c28aaSamw 			goto trans_err_not_supported;
1432da6c28aaSamw 		}
1433da6c28aaSamw 	} else {
1434da6c28aaSamw 		if ((utf8_strcasecmp(xa->xa_smb_trans_name,
1435da6c28aaSamw 		    PIPE_LANMAN) != 0) &&
1436da6c28aaSamw 		    (utf8_strcasecmp(
1437da6c28aaSamw 		    xa->xa_smb_trans_name, MAILSLOT_LANMAN) != 0) &&
1438da6c28aaSamw 		    (utf8_strcasecmp(
1439da6c28aaSamw 		    xa->xa_smb_trans_name, MAILSLOT_BROWSE) != 0) &&
1440da6c28aaSamw 		    (utf8_strcasecmp(
1441da6c28aaSamw 		    xa->xa_smb_trans_name, MAILSLOT_MSBROWSE) != 0))
1442da6c28aaSamw 			goto trans_err_not_supported;
1443da6c28aaSamw 
1444*3ad684d6Sjb150015 		if ((rc = smb_decode_mbc(&xa->req_param_mb, "%wss", sr,
1445da6c28aaSamw 		    &opcode, &req_fmt, &rep_fmt)) != 0)
1446da6c28aaSamw 			goto trans_err_not_supported;
1447da6c28aaSamw 
1448da6c28aaSamw 		switch (opcode) {
1449da6c28aaSamw 		case API_WshareEnum:
1450da6c28aaSamw 			rc = smb_trans_net_share_enum(sr, xa);
1451da6c28aaSamw 			break;
1452da6c28aaSamw 
1453da6c28aaSamw 		case API_WshareGetInfo:
1454*3ad684d6Sjb150015 			rc = smb_trans_net_share_getinfo(sr, xa);
1455da6c28aaSamw 			break;
1456da6c28aaSamw 
1457da6c28aaSamw 		case API_WserverGetInfo:
1458*3ad684d6Sjb150015 			rc = smb_trans_net_server_getinfo(sr, xa);
1459da6c28aaSamw 			break;
1460da6c28aaSamw 
1461da6c28aaSamw 		case API_WUserGetInfo:
1462*3ad684d6Sjb150015 			rc = smb_trans_net_user_getinfo(sr, xa);
1463da6c28aaSamw 			break;
1464da6c28aaSamw 
1465da6c28aaSamw 		case API_WWkstaGetInfo:
1466*3ad684d6Sjb150015 			rc = smb_trans_net_workstation_getinfo(sr, xa);
1467da6c28aaSamw 			break;
1468da6c28aaSamw 
1469da6c28aaSamw 		case API_NetServerEnum2:
1470da6c28aaSamw 			rc = smb_trans_net_server_enum2(sr, xa);
1471da6c28aaSamw 			break;
1472da6c28aaSamw 
1473da6c28aaSamw 		default:
1474da6c28aaSamw 			goto trans_err_not_supported;
1475da6c28aaSamw 		}
1476da6c28aaSamw 	}
1477da6c28aaSamw 
1478da6c28aaSamw 	switch (rc) {
1479faa1795aSjb150015 	case SDRC_SUCCESS:
1480da6c28aaSamw 		break;
1481da6c28aaSamw 
1482da6c28aaSamw 	case SDRC_DROP_VC:
1483da6c28aaSamw 	case SDRC_NO_REPLY:
1484faa1795aSjb150015 	case SDRC_ERROR:
1485da6c28aaSamw 		return (rc);
1486da6c28aaSamw 
1487faa1795aSjb150015 	case SDRC_NOT_IMPLEMENTED:
1488da6c28aaSamw 		goto trans_err_not_supported;
1489da6c28aaSamw 
1490da6c28aaSamw 	default:
1491da6c28aaSamw 		break;
1492da6c28aaSamw 	}
1493da6c28aaSamw 
1494da6c28aaSamw 	n_setup = MBC_LENGTH(&xa->rep_setup_mb);
1495da6c28aaSamw 	n_param = MBC_LENGTH(&xa->rep_param_mb);
1496da6c28aaSamw 	n_data  = MBC_LENGTH(&xa->rep_data_mb);
1497da6c28aaSamw 
1498da6c28aaSamw 	if (xa->smb_msrcnt < n_setup ||
1499da6c28aaSamw 	    xa->smb_mprcnt < n_param ||
1500da6c28aaSamw 	    xa->smb_mdrcnt < n_data) {
1501da6c28aaSamw 		goto trans_err_too_small;
1502da6c28aaSamw 	}
1503da6c28aaSamw 
1504da6c28aaSamw 	/* neato, blast it over there */
1505da6c28aaSamw 
1506da6c28aaSamw 	n_setup = (n_setup + 1) / 2;		/* Convert to setup words */
1507da6c28aaSamw 	param_pad = 1;				/* always one */
1508da6c28aaSamw 	param_off = param_pad + 32 + 21 + (n_setup << 1) + 2;
1509da6c28aaSamw 	data_pad = (param_off + n_param) & 1;	/* Pad to short */
1510da6c28aaSamw 	/* Param off from hdr start */
1511da6c28aaSamw 	data_off = param_off + n_param + data_pad;
1512da6c28aaSamw 	total_bytes = param_pad + n_param + data_pad + n_data;
1513da6c28aaSamw 
15147b59d02dSjb150015 	rc = smbsr_encode_result(sr, 10+n_setup, total_bytes,
1515da6c28aaSamw 	    "b ww 2. www www b . C w #. C #. C",
1516da6c28aaSamw 	    10 + n_setup,		/* wct */
1517da6c28aaSamw 	    n_param,			/* Total Parameter Bytes */
1518da6c28aaSamw 	    n_data,			/* Total Data Bytes */
1519da6c28aaSamw 	    n_param,			/* Total Parameter Bytes this buffer */
1520da6c28aaSamw 	    param_off,			/* Param offset from header start */
1521da6c28aaSamw 	    0,				/* Param displacement */
1522da6c28aaSamw 	    n_data,			/* Total Data Bytes this buffer */
1523da6c28aaSamw 	    data_off,			/* Data offset from header start */
1524da6c28aaSamw 	    0,				/* Data displacement */
1525da6c28aaSamw 	    n_setup,			/* suwcnt */
1526da6c28aaSamw 	    &xa->rep_setup_mb, /* setup[] */
1527da6c28aaSamw 	    total_bytes,		/* Total data bytes */
1528da6c28aaSamw 	    param_pad,
1529da6c28aaSamw 	    &xa->rep_param_mb,
1530da6c28aaSamw 	    data_pad,
1531da6c28aaSamw 	    &xa->rep_data_mb);
1532faa1795aSjb150015 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
1533da6c28aaSamw 
1534da6c28aaSamw trans_err_too_small:
1535da6c28aaSamw 	rc = NERR_BufTooSmall;
1536da6c28aaSamw 	goto trans_err;
1537da6c28aaSamw 
1538da6c28aaSamw trans_err_not_supported:
1539da6c28aaSamw 	rc = ERROR_NOT_SUPPORTED;
1540da6c28aaSamw 	goto trans_err;
1541da6c28aaSamw 
1542da6c28aaSamw trans_err:
1543da6c28aaSamw 	pos = MBC_LENGTH(&sr->reply) + 23;
15447b59d02dSjb150015 	rc = smbsr_encode_result(sr, 10, 4, "b ww 2. www www b . w ww",
1545da6c28aaSamw 	    10,		/* wct */
1546da6c28aaSamw 	    4, 0,	/* tpscnt tdscnt */
1547da6c28aaSamw 	    4, pos, 0,	/* pscnt psoff psdisp */
1548da6c28aaSamw 	    0, 0, 0,	/* dscnt dsoff dsdisp */
1549da6c28aaSamw 	    0,		/* suwcnt */
1550da6c28aaSamw 	    4,		/* bcc */
1551da6c28aaSamw 	    rc,
1552da6c28aaSamw 	    0);		/* converter word? */
1553faa1795aSjb150015 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
1554da6c28aaSamw }
1555da6c28aaSamw 
15567b59d02dSjb150015 static smb_sdrc_t
1557da6c28aaSamw smb_trans2_dispatch(struct smb_request *sr, struct smb_xa *xa)
1558da6c28aaSamw {
1559da6c28aaSamw 	int		rc, pos;
1560da6c28aaSamw 	int		total_bytes, n_setup, n_param, n_data;
1561da6c28aaSamw 	int		param_off, param_pad, data_off, data_pad;
1562da6c28aaSamw 	uint16_t	opcode;
1563da6c28aaSamw 	uint16_t  nt_unknown_secret = 0x0100;
1564da6c28aaSamw 	char *fmt;
1565da6c28aaSamw 
1566da6c28aaSamw 	n_setup = (xa->smb_msrcnt < 200) ? xa->smb_msrcnt : 200;
1567da6c28aaSamw 	n_setup++;
1568da6c28aaSamw 	n_setup = n_setup & ~0x0001;
1569da6c28aaSamw 	n_param = (xa->smb_mprcnt < smb_maxbufsize)
1570da6c28aaSamw 	    ? xa->smb_mprcnt : smb_maxbufsize;
1571da6c28aaSamw 	n_param++;
1572da6c28aaSamw 	n_param = n_param & ~0x0001;
1573da6c28aaSamw 	rc = smb_maxbufsize - (SMBHEADERSIZE + 28 + n_setup + n_param);
1574da6c28aaSamw 	n_data =  (xa->smb_mdrcnt < rc) ? xa->smb_mdrcnt : rc;
1575da6c28aaSamw 	MBC_INIT(&xa->rep_setup_mb, n_setup * 2);
1576da6c28aaSamw 	MBC_INIT(&xa->rep_param_mb, n_param);
1577da6c28aaSamw 	MBC_INIT(&xa->rep_data_mb, n_data);
1578da6c28aaSamw 
1579da6c28aaSamw 	if (smb_decode_mbc(&xa->req_setup_mb, "w", &opcode) != 0)
1580da6c28aaSamw 		goto trans_err_not_supported;
1581da6c28aaSamw 
1582da6c28aaSamw 	/*
1583da6c28aaSamw 	 * Save this for /proc to read later.
1584da6c28aaSamw 	 */
1585da6c28aaSamw 	xa->smb_func = opcode;
1586da6c28aaSamw 
1587da6c28aaSamw 	/* for now, only respond to the */
1588da6c28aaSamw 	switch (opcode) {
1589da6c28aaSamw 	case TRANS2_CREATE_DIRECTORY:
1590da6c28aaSamw 		rc = smb_com_trans2_create_directory(sr, xa);
1591da6c28aaSamw 		break;
1592da6c28aaSamw 
1593da6c28aaSamw 	case TRANS2_FIND_FIRST2:
1594da6c28aaSamw 		/*
1595da6c28aaSamw 		 * Should have enough room to send the response
1596da6c28aaSamw 		 * data back to client.
1597da6c28aaSamw 		 */
1598da6c28aaSamw 		if (n_data == 0) {
1599dc20a302Sas200622 			smbsr_error(sr, NT_STATUS_INFO_LENGTH_MISMATCH,
1600da6c28aaSamw 			    ERRDOS, ERROR_BAD_LENGTH);
1601faa1795aSjb150015 			return (SDRC_ERROR);
1602da6c28aaSamw 		}
1603da6c28aaSamw 		rc = smb_com_trans2_find_first2(sr, xa);
1604da6c28aaSamw 		break;
1605da6c28aaSamw 
1606da6c28aaSamw 	case TRANS2_FIND_NEXT2:
1607da6c28aaSamw 		/*
1608da6c28aaSamw 		 * Should have enough room to send the response
1609da6c28aaSamw 		 * data back to client.
1610da6c28aaSamw 		 */
1611da6c28aaSamw 		if (n_data == 0) {
1612dc20a302Sas200622 			smbsr_error(sr, NT_STATUS_INFO_LENGTH_MISMATCH,
1613da6c28aaSamw 			    ERRDOS, ERROR_BAD_LENGTH);
1614faa1795aSjb150015 			return (SDRC_ERROR);
1615da6c28aaSamw 		}
1616da6c28aaSamw 		rc = smb_com_trans2_find_next2(sr, xa);
1617da6c28aaSamw 		break;
1618da6c28aaSamw 
1619da6c28aaSamw 	case TRANS2_QUERY_FS_INFORMATION:
1620da6c28aaSamw 		/*
1621da6c28aaSamw 		 * Should have enough room to send the response
1622da6c28aaSamw 		 * data back to client.
1623da6c28aaSamw 		 */
1624da6c28aaSamw 		if (n_data == 0) {
1625dc20a302Sas200622 			smbsr_error(sr, NT_STATUS_INFO_LENGTH_MISMATCH,
1626da6c28aaSamw 			    ERRDOS, ERROR_BAD_LENGTH);
1627faa1795aSjb150015 			return (SDRC_ERROR);
1628da6c28aaSamw 		}
1629da6c28aaSamw 		rc = smb_com_trans2_query_fs_information(sr, xa);
1630da6c28aaSamw 		break;
1631da6c28aaSamw 
1632da6c28aaSamw 	case TRANS2_QUERY_PATH_INFORMATION:
1633da6c28aaSamw 		/*
1634da6c28aaSamw 		 * Should have enough room to send the response
1635da6c28aaSamw 		 * data back to client.
1636da6c28aaSamw 		 */
1637da6c28aaSamw 		if (n_data == 0) {
1638dc20a302Sas200622 			smbsr_error(sr, NT_STATUS_INFO_LENGTH_MISMATCH,
1639da6c28aaSamw 			    ERRDOS, ERROR_BAD_LENGTH);
1640faa1795aSjb150015 			return (SDRC_ERROR);
1641da6c28aaSamw 		}
1642da6c28aaSamw 		rc = smb_com_trans2_query_path_information(sr, xa);
1643da6c28aaSamw 		break;
1644da6c28aaSamw 
1645da6c28aaSamw 	case TRANS2_QUERY_FILE_INFORMATION:
1646da6c28aaSamw 		/*
1647da6c28aaSamw 		 * Should have enough room to send the response
1648da6c28aaSamw 		 * data back to client.
1649da6c28aaSamw 		 */
1650da6c28aaSamw 		if (n_data == 0) {
1651dc20a302Sas200622 			smbsr_error(sr, NT_STATUS_INFO_LENGTH_MISMATCH,
1652da6c28aaSamw 			    ERRDOS, ERROR_BAD_LENGTH);
1653faa1795aSjb150015 			return (SDRC_ERROR);
1654da6c28aaSamw 		}
1655da6c28aaSamw 		rc = smb_com_trans2_query_file_information(sr, xa);
1656da6c28aaSamw 		break;
1657da6c28aaSamw 
1658da6c28aaSamw 	case TRANS2_SET_PATH_INFORMATION:
1659da6c28aaSamw 		rc = smb_com_trans2_set_path_information(sr, xa);
1660da6c28aaSamw 		break;
1661da6c28aaSamw 
1662da6c28aaSamw 	case TRANS2_SET_FILE_INFORMATION:
1663da6c28aaSamw 		rc = smb_com_trans2_set_file_information(sr, xa);
1664da6c28aaSamw 		break;
1665da6c28aaSamw 	default:
1666da6c28aaSamw 		goto trans_err_not_supported;
1667da6c28aaSamw 	}
1668da6c28aaSamw 
1669da6c28aaSamw 	switch (rc) {
1670faa1795aSjb150015 	case SDRC_SUCCESS:
1671da6c28aaSamw 		break;
1672da6c28aaSamw 
1673da6c28aaSamw 	case SDRC_DROP_VC:
1674da6c28aaSamw 	case SDRC_NO_REPLY:
1675faa1795aSjb150015 	case SDRC_ERROR:
1676da6c28aaSamw 		return (rc);
1677da6c28aaSamw 
1678faa1795aSjb150015 	case SDRC_NOT_IMPLEMENTED:
1679da6c28aaSamw 		goto trans_err_not_supported;
1680da6c28aaSamw 
1681da6c28aaSamw 	default:
1682da6c28aaSamw 		break;
1683da6c28aaSamw 	}
1684da6c28aaSamw 
1685da6c28aaSamw 	n_setup = MBC_LENGTH(&xa->rep_setup_mb);
1686da6c28aaSamw 	n_param = MBC_LENGTH(&xa->rep_param_mb);
1687da6c28aaSamw 	n_data  = MBC_LENGTH(&xa->rep_data_mb);
1688da6c28aaSamw 
1689da6c28aaSamw 	if (xa->smb_msrcnt < n_setup ||
1690da6c28aaSamw 	    xa->smb_mprcnt < n_param ||
1691da6c28aaSamw 	    xa->smb_mdrcnt < n_data) {
1692da6c28aaSamw 		goto trans_err_too_small;
1693da6c28aaSamw 	}
1694da6c28aaSamw 
1695da6c28aaSamw 	/* neato, blast it over there */
1696da6c28aaSamw 
1697da6c28aaSamw 	n_setup = (n_setup + 1) / 2;		/* Conver to setup words */
1698da6c28aaSamw 	param_pad = 1;				/* must be one */
1699da6c28aaSamw 	param_off = param_pad + 32 + 21 + (n_setup << 1) + 2;
1700da6c28aaSamw 
1701da6c28aaSamw 	/*
1702da6c28aaSamw 	 * Including the nt_unknown_secret value persuades netmon to
1703da6c28aaSamw 	 * display the correct data format for QueryPathInfo and
1704da6c28aaSamw 	 * QueryFileInfo.
1705da6c28aaSamw 	 */
1706da6c28aaSamw 	if (opcode == TRANS2_QUERY_FILE_INFORMATION ||
1707da6c28aaSamw 	    opcode == TRANS2_QUERY_PATH_INFORMATION) {
1708da6c28aaSamw 		data_pad = sizeof (uint16_t);
1709da6c28aaSamw 		data_off = param_off + n_param + data_pad;
1710da6c28aaSamw 		fmt = "b ww 2. www www b . C w #. C w C";
1711da6c28aaSamw 		nt_unknown_secret = 0x0100;
1712da6c28aaSamw 	}
1713da6c28aaSamw 	else
1714da6c28aaSamw 	{
1715da6c28aaSamw 		data_pad = (param_off + n_param) & 1; /* Pad to short */
1716da6c28aaSamw 		/* Param off from hdr start */
1717da6c28aaSamw 		data_off = param_off + n_param + data_pad;
1718da6c28aaSamw 		fmt = "b ww 2. www www b . C w #. C #. C";
1719da6c28aaSamw 		/*LINTED E_ASSIGN_NARROW_CONV*/
1720da6c28aaSamw 		nt_unknown_secret = data_pad;
1721da6c28aaSamw 	}
1722da6c28aaSamw 
1723da6c28aaSamw 	total_bytes = param_pad + n_param + data_pad + n_data;
1724da6c28aaSamw 
17257b59d02dSjb150015 	rc = smbsr_encode_result(sr, 10+n_setup, total_bytes,
1726da6c28aaSamw 	    fmt,
1727da6c28aaSamw 	    10 + n_setup,		/* wct */
1728da6c28aaSamw 	    n_param,			/* Total Parameter Bytes */
1729da6c28aaSamw 	    n_data /* + data_pad */,	/* Total Data Bytes */
1730da6c28aaSamw 	    n_param,			/* Total Parameter Bytes this buffer */
1731da6c28aaSamw 	    param_off,			/* Param offset from header start */
1732da6c28aaSamw 	    0,				/* Param displacement */
1733da6c28aaSamw 	    n_data /* + data_pad */,	/* Total Data Bytes this buffer */
1734da6c28aaSamw 	    data_off,			/* Data offset from header start */
1735da6c28aaSamw 	    0,				/* Data displacement */
1736da6c28aaSamw 	    n_setup,			/* suwcnt */
1737da6c28aaSamw 	    &xa->rep_setup_mb,		/* setup[] */
1738da6c28aaSamw 	    total_bytes,		/* Total data bytes */
1739da6c28aaSamw 	    param_pad,
1740da6c28aaSamw 	    &xa->rep_param_mb,
1741da6c28aaSamw 	    nt_unknown_secret,
1742da6c28aaSamw 	    &xa->rep_data_mb);
1743faa1795aSjb150015 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
1744da6c28aaSamw 
1745da6c28aaSamw trans_err_too_small:
1746da6c28aaSamw 	rc = NERR_BufTooSmall;
1747da6c28aaSamw 	goto trans_err;
1748da6c28aaSamw 
1749da6c28aaSamw trans_err_not_supported:
1750da6c28aaSamw 	rc = ERROR_NOT_SUPPORTED;
1751da6c28aaSamw 	goto trans_err;
1752da6c28aaSamw 
1753da6c28aaSamw trans_err:
1754da6c28aaSamw 	pos = MBC_LENGTH(&sr->reply) + 23;
17557b59d02dSjb150015 	rc = smbsr_encode_result(sr, 10, 4, "b ww 2. www www b . w ww",
1756da6c28aaSamw 	    10,		/* wct */
1757da6c28aaSamw 	    4, 0,	/* tpscnt tdscnt */
1758da6c28aaSamw 	    4, pos, 0,	/* pscnt psoff psdisp */
1759da6c28aaSamw 	    0, 0, 0,	/* dscnt dsoff dsdisp */
1760da6c28aaSamw 	    0,		/* suwcnt */
1761da6c28aaSamw 	    4,		/* bcc */
1762da6c28aaSamw 	    rc,
1763da6c28aaSamw 	    0);		/* converter word? */
1764faa1795aSjb150015 	return ((rc == 0) ? SDRC_SUCCESS : SDRC_ERROR);
1765da6c28aaSamw }
1766da6c28aaSamw 
1767da6c28aaSamw smb_xa_t *
1768da6c28aaSamw smb_xa_create(
1769da6c28aaSamw     smb_session_t	*session,
1770da6c28aaSamw     smb_request_t	*sr,
1771da6c28aaSamw     uint32_t		total_parameter_count,
1772da6c28aaSamw     uint32_t		total_data_count,
1773da6c28aaSamw     uint32_t		max_parameter_count,
1774da6c28aaSamw     uint32_t		max_data_count,
1775da6c28aaSamw     uint32_t		max_setup_count,
1776da6c28aaSamw     uint32_t		setup_word_count)
1777da6c28aaSamw {
1778da6c28aaSamw 	smb_xa_t	*xa, *nxa;
1779da6c28aaSamw 	smb_llist_t	*xlist;
1780da6c28aaSamw 
1781da6c28aaSamw 	xa = MEM_ZALLOC("xa", sizeof (smb_xa_t));
1782da6c28aaSamw 	xa->xa_refcnt = 1;
1783da6c28aaSamw 	xa->smb_com = sr->smb_com;
1784da6c28aaSamw 	xa->smb_flg = sr->smb_flg;
1785da6c28aaSamw 	xa->smb_flg2 = sr->smb_flg2;
1786da6c28aaSamw 	xa->smb_tid = sr->smb_tid;
1787da6c28aaSamw 	xa->smb_pid = sr->smb_pid;
1788da6c28aaSamw 	xa->smb_uid = sr->smb_uid;
1789da6c28aaSamw 	xa->xa_smb_mid = sr->smb_mid;
1790da6c28aaSamw 	xa->reply_seqnum = sr->reply_seqnum;
1791da6c28aaSamw 	xa->smb_tpscnt = total_parameter_count;
1792da6c28aaSamw 	xa->smb_tdscnt = total_data_count;
1793da6c28aaSamw 	xa->smb_mprcnt = max_parameter_count;
1794da6c28aaSamw 	xa->smb_mdrcnt = max_data_count;
1795da6c28aaSamw 	xa->smb_msrcnt = max_setup_count;
1796da6c28aaSamw 	xa->smb_suwcnt = setup_word_count;
1797da6c28aaSamw 	xa->xa_session = session;
1798da6c28aaSamw 	xa->xa_magic = SMB_XA_MAGIC;
1799da6c28aaSamw 
1800da6c28aaSamw 	/*
1801da6c28aaSamw 	 * The new xa structure is checked against the current list to see
1802da6c28aaSamw 	 * if it exists already.
1803da6c28aaSamw 	 */
1804da6c28aaSamw 	xlist = &session->s_xa_list;
1805da6c28aaSamw 	smb_llist_enter(xlist, RW_WRITER);
1806da6c28aaSamw 	nxa = smb_llist_head(xlist);
1807da6c28aaSamw 	while (nxa) {
1808da6c28aaSamw 		ASSERT(nxa->xa_magic == SMB_XA_MAGIC);
1809da6c28aaSamw 		if (nxa->xa_smb_mid == xa->xa_smb_mid &&
1810da6c28aaSamw 		    nxa->smb_pid == xa->smb_pid &&
1811da6c28aaSamw 		    !SMB_XA_CLOSED(nxa) &&
1812da6c28aaSamw 		    !(nxa->xa_flags & SMB_XA_FLAG_COMPLETE)) {
1813da6c28aaSamw 			smb_llist_exit(xlist);
1814da6c28aaSamw 			MEM_FREE("xa", xa);
1815da6c28aaSamw 			return (NULL);
1816da6c28aaSamw 		}
1817da6c28aaSamw 		nxa = smb_llist_next(xlist, nxa);
1818da6c28aaSamw 	}
1819da6c28aaSamw 	smb_llist_insert_tail(xlist, xa);
1820da6c28aaSamw 	smb_llist_exit(xlist);
1821da6c28aaSamw 	return (xa);
1822da6c28aaSamw }
1823da6c28aaSamw 
1824da6c28aaSamw void
1825da6c28aaSamw smb_xa_delete(smb_xa_t *xa)
1826da6c28aaSamw {
1827da6c28aaSamw 	ASSERT(xa->xa_refcnt == 0);
1828da6c28aaSamw 	ASSERT(SMB_XA_CLOSED(xa));
1829da6c28aaSamw 
1830da6c28aaSamw 	if (xa->xa_smb_trans_name)
1831da6c28aaSamw 		MEM_FREE("smb", xa->xa_smb_trans_name);
1832da6c28aaSamw 
1833da6c28aaSamw 	if (xa->rep_setup_mb.chain != NULL)
1834da6c28aaSamw 		m_freem(xa->rep_setup_mb.chain);
1835da6c28aaSamw 	if (xa->rep_param_mb.chain != NULL)
1836da6c28aaSamw 		m_freem(xa->rep_param_mb.chain);
1837da6c28aaSamw 	if (xa->rep_data_mb.chain != NULL)
1838da6c28aaSamw 		m_freem(xa->rep_data_mb.chain);
1839da6c28aaSamw 
1840da6c28aaSamw 	xa->xa_magic = (uint32_t)~SMB_XA_MAGIC;
1841da6c28aaSamw 	MEM_FREE("xa", xa);
1842da6c28aaSamw }
1843da6c28aaSamw 
1844da6c28aaSamw smb_xa_t *
1845da6c28aaSamw smb_xa_hold(smb_xa_t *xa)
1846da6c28aaSamw {
1847da6c28aaSamw 	mutex_enter(&xa->xa_mutex);
1848da6c28aaSamw 	xa->xa_refcnt++;
1849da6c28aaSamw 	ASSERT(xa->xa_refcnt);
1850da6c28aaSamw 	mutex_exit(&xa->xa_mutex);
1851da6c28aaSamw 	return (xa);
1852da6c28aaSamw }
1853da6c28aaSamw 
1854da6c28aaSamw void
1855da6c28aaSamw smb_xa_rele(smb_session_t *session, smb_xa_t *xa)
1856da6c28aaSamw {
1857da6c28aaSamw 	mutex_enter(&xa->xa_mutex);
1858da6c28aaSamw 	ASSERT(xa->xa_refcnt);
1859da6c28aaSamw 	xa->xa_refcnt--;
1860da6c28aaSamw 	if (SMB_XA_CLOSED(xa) && (xa->xa_refcnt == 0)) {
1861da6c28aaSamw 		mutex_exit(&xa->xa_mutex);
1862da6c28aaSamw 		smb_llist_enter(&session->s_xa_list, RW_WRITER);
1863da6c28aaSamw 		smb_llist_remove(&session->s_xa_list, xa);
1864da6c28aaSamw 		smb_llist_exit(&session->s_xa_list);
1865da6c28aaSamw 		smb_xa_delete(xa);
1866da6c28aaSamw 		return;
1867da6c28aaSamw 	}
1868da6c28aaSamw 	mutex_exit(&xa->xa_mutex);
1869da6c28aaSamw }
1870da6c28aaSamw 
1871da6c28aaSamw int
1872da6c28aaSamw smb_xa_open(smb_xa_t *xa)
1873da6c28aaSamw {
1874da6c28aaSamw 	int rc;
1875da6c28aaSamw 
1876da6c28aaSamw 	mutex_enter(&xa->xa_mutex);
1877da6c28aaSamw 
1878da6c28aaSamw 	ASSERT((xa->xa_flags & SMB_XA_FLAG_OPEN) == 0);
1879da6c28aaSamw 
1880da6c28aaSamw 	if ((xa->xa_flags & SMB_XA_FLAG_CLOSE) == 0) {
1881da6c28aaSamw 		xa->xa_flags |= SMB_XA_FLAG_OPEN;
1882da6c28aaSamw 		rc = 0;
1883da6c28aaSamw 	} else {
1884da6c28aaSamw 		rc = ERROR_INVALID_HANDLE;
1885da6c28aaSamw 	}
1886da6c28aaSamw 
1887da6c28aaSamw 	mutex_exit(&xa->xa_mutex);
1888da6c28aaSamw 
1889da6c28aaSamw 	return (rc);
1890da6c28aaSamw }
1891da6c28aaSamw 
1892da6c28aaSamw void
1893da6c28aaSamw smb_xa_close(smb_xa_t *xa)
1894da6c28aaSamw {
1895da6c28aaSamw 	mutex_enter(&xa->xa_mutex);
1896da6c28aaSamw 	xa->xa_flags |= SMB_XA_FLAG_CLOSE;
1897da6c28aaSamw 	xa->xa_flags &= ~SMB_XA_FLAG_OPEN;
1898da6c28aaSamw 
1899da6c28aaSamw 	if (xa->xa_refcnt == 0) {
1900da6c28aaSamw 		mutex_exit(&xa->xa_mutex);
1901da6c28aaSamw 		smb_llist_enter(&xa->xa_session->s_xa_list, RW_WRITER);
1902da6c28aaSamw 		smb_llist_remove(&xa->xa_session->s_xa_list, xa);
1903da6c28aaSamw 		smb_llist_exit(&xa->xa_session->s_xa_list);
1904da6c28aaSamw 		smb_xa_delete(xa);
1905da6c28aaSamw 		return;
1906da6c28aaSamw 	}
1907da6c28aaSamw 
1908da6c28aaSamw 	mutex_exit(&xa->xa_mutex);
1909da6c28aaSamw }
1910da6c28aaSamw 
1911da6c28aaSamw int
1912da6c28aaSamw smb_xa_complete(smb_xa_t *xa)
1913da6c28aaSamw {
1914da6c28aaSamw 	int rc;
1915da6c28aaSamw 
1916da6c28aaSamw 	mutex_enter(&xa->xa_mutex);
1917da6c28aaSamw 	if (xa->xa_flags & (SMB_XA_FLAG_COMPLETE | SMB_XA_FLAG_CLOSE)) {
1918da6c28aaSamw 		rc = 0;
1919da6c28aaSamw 	} else {
1920da6c28aaSamw 		rc = 1;
1921da6c28aaSamw 		xa->xa_flags |= SMB_XA_FLAG_COMPLETE;
1922da6c28aaSamw 	}
1923da6c28aaSamw 	mutex_exit(&xa->xa_mutex);
1924da6c28aaSamw 	return (rc);
1925da6c28aaSamw }
1926da6c28aaSamw 
1927da6c28aaSamw smb_xa_t *
1928da6c28aaSamw smb_xa_find(
1929da6c28aaSamw     smb_session_t	*session,
1930da6c28aaSamw     uint16_t		pid,
1931da6c28aaSamw     uint16_t		mid)
1932da6c28aaSamw {
1933da6c28aaSamw 	smb_xa_t	*xa;
1934da6c28aaSamw 	smb_llist_t	*xlist;
1935da6c28aaSamw 
1936da6c28aaSamw 	xlist = &session->s_xa_list;
1937da6c28aaSamw 	smb_llist_enter(xlist, RW_READER);
1938da6c28aaSamw 	xa = smb_llist_head(xlist);
1939da6c28aaSamw 	while (xa) {
1940da6c28aaSamw 		mutex_enter(&xa->xa_mutex);
1941da6c28aaSamw 		if (xa->xa_smb_mid == mid &&
1942da6c28aaSamw 		    xa->smb_pid == pid &&
1943da6c28aaSamw 		    !SMB_XA_CLOSED(xa) &&
1944da6c28aaSamw 		    !(xa->xa_flags & SMB_XA_FLAG_COMPLETE)) {
1945da6c28aaSamw 			xa->xa_refcnt++;
1946da6c28aaSamw 			ASSERT(xa->xa_refcnt);
1947da6c28aaSamw 			mutex_exit(&xa->xa_mutex);
1948da6c28aaSamw 			break;
1949da6c28aaSamw 		}
1950da6c28aaSamw 		mutex_exit(&xa->xa_mutex);
1951da6c28aaSamw 		xa = smb_llist_next(xlist, xa);
1952da6c28aaSamw 	}
1953da6c28aaSamw 	smb_llist_exit(xlist);
1954da6c28aaSamw 	return (xa);
1955da6c28aaSamw }
1956