xref: /titanic_50/usr/src/uts/common/fs/smbsrv/smb_dispatch.c (revision 15d9d0b528387242011cdcc6190c9e598cfe3a07)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  *
25  *
26  * Dispatching SMB requests.
27  */
28 
29 #pragma ident	"%Z%%M%	%I%	%E% SMI"
30 
31 /*
32  * ALMOST EVERYTHING YOU NEED TO KNOW ABOUT A SERVER MESSAGE BLOCK
33  *
34  * Request
35  *   Header
36  *	Magic		0xFF 'S' 'M' 'B'
37  *	smb_com 	a byte, the "first" command
38  *	Error		a 4-byte union, ignored in a request
39  *	smb_flg		a one byte set of eight flags
40  *	smb_flg2	a two byte set of 16 flags
41  *	.		twelve reserved bytes, have a role
42  *			in connectionless transports (IPX, UDP?)
43  *	smb_tid		a 16-bit tree ID, a mount point sorta,
44  *			0xFFFF is this command does not have
45  *			or require a tree context
46  *	smb_pid		a 16-bit process ID
47  *	smb_uid		a 16-bit user ID, specific to this "session"
48  *			and mapped to a system (bona-fide) UID
49  *	smb_mid		a 16-bit multiplex ID, used to differentiate
50  *			multiple simultaneous requests from the same
51  *			process (pid) (ref RPC "xid")
52  *
53  *   Chained (AndX) commands (0 or more)
54  *	smb_wct		a byte, number of 16-bit words containing
55  *			command parameters, min 2 for chained command
56  *	andx_com	a byte, the "next" command, 0xFF for none
57  *	.		an unused byte
58  *	andx_off	a 16-bit offset, byte displacement from &Magic
59  *			to the smb_wct field of the "next" command,
60  *			ignore if andx_com is 0xFF, s/b 0 if no next
61  *	smb_vwv[]	0 or more 16-bit (sorta) parameters for
62  *			"this" command (i.e. smb_com if this is the
63  *			first parameters, or the andx_com of the just
64  *			previous block.
65  *	smb_bcc		a 16-bit count of smb_data[] bytes
66  *	smb_data[]	0 or more bytes, format specific to commands
67  *	padding[]	Optional padding
68  *
69  *   Last command
70  *	smb_wct		a byte, number of 16-bit words containing
71  *			command parameters, min 0 for chained command
72  *	smb_vwv[]	0 or more 16-bit (sorta) parameters for
73  *			"this" command (i.e. smb_com if this is the
74  *			first parameters, or the andx_com of the just
75  *			previous block.
76  *	smb_bcc		a 16-bit count of smb_data[] bytes
77  *	smb_data[]	0 or more bytes, format specific to commands
78  *
79  * Reply
80  *   Header
81  *	Magic		0xFF 'S' 'M' 'B'
82  *	smb_com 	a byte, the "first" command, corresponds
83  *			to request
84  *	Error		a 4-byte union, coding depends on dialect in use
85  *			for "DOS" errors
86  *				a byte for error class
87  *				an unused byte
88  *				a 16-bit word for error code
89  *			for "NT" errors
90  *				a 32-bit error code which
91  *				is a packed class and specifier
92  *			for "OS/2" errors
93  *				I don't know
94  *			The error information is specific to the
95  *			last command in the reply chain.
96  *	smb_flg		a one byte set of eight flags, 0x80 bit set
97  *			indicating this message is a reply
98  *	smb_flg2	a two byte set of 16 flags
99  *	.		twelve reserved bytes, have a role
100  *			in connectionless transports (IPX, UDP?)
101  *	smb_tid		a 16-bit tree ID, a mount point sorta,
102  *			should be the same as the request
103  *	smb_pid		a 16-bit process ID, MUST BE the same as request
104  *	smb_uid		a 16-bit user ID, specific to this "session"
105  *			and mapped to a system (bona-fide) UID,
106  *			should be the same as request
107  *	smb_mid		a 16-bit multiplex ID, used to differentiate
108  *			multiple simultaneous requests from the same
109  *			process (pid) (ref RPC "xid"), MUST BE the
110  *			same as request
111  *	padding[]	Optional padding
112  *
113  *   Chained (AndX) commands (0 or more)
114  *	smb_wct		a byte, number of 16-bit words containing
115  *			command parameters, min 2 for chained command,
116  *	andx_com	a byte, the "next" command, 0xFF for none,
117  *			corresponds to request, if this is the chained
118  *			command that had an error set to 0xFF
119  *	.		an unused byte
120  *	andx_off	a 16-bit offset, byte displacement from &Magic
121  *			to the smb_wct field of the "next" command,
122  *			ignore if andx_com is 0xFF, s/b 0 if no next
123  *	smb_vwv[]	0 or more 16-bit (sorta) parameters for
124  *			"this" command (i.e. smb_com if this is the
125  *			first parameters, or the andx_com of the just
126  *			previous block. Empty if an error.
127  *	smb_bcc		a 16-bit count of smb_data[] bytes
128  *	smb_data[]	0 or more bytes, format specific to commands
129  *			empty if an error.
130  *
131  *   Last command
132  *	smb_wct		a byte, number of 16-bit words containing
133  *			command parameters, min 0 for chained command
134  *	smb_vwv[]	0 or more 16-bit (sorta) parameters for
135  *			"this" command (i.e. smb_com if this is the
136  *			first parameters, or the andx_com of the just
137  *			previous block, empty if an error.
138  *	smb_bcc		a 16-bit count of smb_data[] bytes
139  *	smb_data[]	0 or more bytes, format specific to commands,
140  *			empty if an error.
141  */
142 
143 #include <smbsrv/smb_incl.h>
144 #include <sys/sdt.h>
145 
146 #define	SMB_ALL_DISPATCH_STAT_INCR(stat)	atomic_inc_64(&stat);
147 
148 static kstat_t *smb_dispatch_ksp = NULL;
149 static kstat_named_t *smb_dispatch_kstat_data = NULL;
150 static int smb_dispatch_kstat_size = 0;
151 
152 static int 	is_andx_com(unsigned char);
153 
154 extern void	smbsr_decode_error(struct smb_request *sr);
155 extern void	smbsr_encode_error(struct smb_request *sr);
156 extern void	smbsr_check_result(struct smb_request *sr, int wct, int bcc);
157 
158 extern int	smb_com_cancel_forward(struct smb_request *);
159 extern int	smb_com_check_directory(struct smb_request *);
160 extern int	smb_com_close(struct smb_request *);
161 extern int	smb_com_close_and_tree_disconnect(struct smb_request *);
162 extern int	smb_com_close_print_file(struct smb_request *);
163 extern int	smb_com_copy(struct smb_request *);
164 extern int	smb_com_create(struct smb_request *);
165 extern int	smb_com_create_directory(struct smb_request *);
166 extern int	smb_com_create_new(struct smb_request *);
167 extern int	smb_com_create_temporary(struct smb_request *);
168 extern int	smb_com_delete(struct smb_request *);
169 extern int	smb_com_delete_directory(struct smb_request *);
170 extern int	smb_com_echo(struct smb_request *);
171 extern int	smb_com_find(struct smb_request *);
172 extern int	smb_com_find_close(struct smb_request *);
173 extern int	smb_com_find_close2(struct smb_request *);
174 extern int	smb_com_find_notify_close(struct smb_request *);
175 extern int	smb_com_find_unique(struct smb_request *);
176 extern int	smb_com_flush(struct smb_request *);
177 extern int	smb_com_forward_user_name(struct smb_request *);
178 extern int	smb_com_get_machine_name(struct smb_request *);
179 extern int	smb_com_get_print_queue(struct smb_request *);
180 extern int	smb_com_invalid_command(struct smb_request *);
181 extern int	smb_com_ioctl(struct smb_request *);
182 extern int	smb_com_ioctl_secondary(struct smb_request *);
183 extern int	smb_com_lock_and_read(struct smb_request *);
184 extern int	smb_com_lock_byte_range(struct smb_request *);
185 extern int	smb_com_locking_andx(struct smb_request *);
186 extern int	smb_com_logoff_andx(struct smb_request *);
187 extern int	smb_com_move(struct smb_request *);
188 extern int	smb_com_negotiate(struct smb_request *);
189 extern int	smb_com_nt_cancel(struct smb_request *);
190 extern int	smb_com_nt_create_andx(struct smb_request *);
191 extern int	smb_com_nt_transact(struct smb_request *);
192 extern int	smb_com_nt_transact_secondary(struct smb_request *);
193 extern int	smb_com_open(struct smb_request *);
194 extern int	smb_com_open_andx(struct smb_request *);
195 extern int	smb_com_open_print_file(struct smb_request *);
196 extern int	smb_com_process_exit(struct smb_request *);
197 extern int	smb_com_query_information(struct smb_request *);
198 extern int	smb_com_query_information2(struct smb_request *);
199 extern int	smb_com_query_information_disk(struct smb_request *);
200 extern int	smb_com_read(struct smb_request *);
201 extern int	smb_com_read_andx(struct smb_request *);
202 extern int	smb_com_read_mpx(struct smb_request *);
203 extern int	smb_com_read_mpx_secondary(struct smb_request *);
204 extern int	smb_com_read_raw(struct smb_request *);
205 extern int	smb_com_rename(struct smb_request *);
206 extern int	smb_com_search(struct smb_request *);
207 extern int	smb_com_seek(struct smb_request *);
208 extern int	smb_com_send_broadcast_message(struct smb_request *);
209 extern int	smb_com_send_end_mb_message(struct smb_request *);
210 extern int	smb_com_send_single_message(struct smb_request *);
211 extern int	smb_com_send_start_mb_message(struct smb_request *);
212 extern int	smb_com_send_text_mb_message(struct smb_request *);
213 extern int	smb_com_session_setup_andx(struct smb_request *);
214 extern int	smb_com_set_information(struct smb_request *);
215 extern int	smb_com_set_information2(struct smb_request *);
216 extern int	smb_com_transaction(struct smb_request *);
217 extern int	smb_com_transaction2(struct smb_request *);
218 extern int	smb_com_transaction2_secondary(struct smb_request *);
219 extern int	smb_com_transaction_secondary(struct smb_request *);
220 extern int	smb_com_tree_connect(struct smb_request *);
221 extern int	smb_com_tree_connect_andx(struct smb_request *);
222 extern int	smb_com_tree_disconnect(struct smb_request *);
223 extern int	smb_com_unlock_byte_range(struct smb_request *);
224 extern int	smb_com_write(struct smb_request *);
225 extern int	smb_com_write_and_close(struct smb_request *);
226 extern int	smb_com_write_and_unlock(struct smb_request *);
227 extern int	smb_com_write_andx(struct smb_request *);
228 extern int	smb_com_write_complete(struct smb_request *);
229 extern int	smb_com_write_mpx(struct smb_request *);
230 extern int	smb_com_write_mpx_secondary(struct smb_request *);
231 extern int	smb_com_write_print_file(struct smb_request *);
232 extern int	smb_com_write_raw(struct smb_request *);
233 
234 static smb_dispatch_table_t	dispatch[256] = {
235 	{ smb_com_create_directory,				/* 0x00 000 */
236 	    PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
237 	    RW_READER,
238 	    { "SmbCreateDirectory", KSTAT_DATA_UINT64 } },
239 	{ smb_com_delete_directory,				/* 0x01 001 */
240 	    PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
241 	    RW_READER,
242 	    { "SmbDeleteDirectory", KSTAT_DATA_UINT64 } },
243 	{ smb_com_open,						/* 0x02 002 */
244 	    PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
245 	    RW_READER,
246 	    { "SmbOpen", KSTAT_DATA_UINT64 } },
247 	{ smb_com_create,					/* 0x03 003 */
248 	    PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
249 	    RW_READER,
250 	    { "SmbCreate", KSTAT_DATA_UINT64 } },
251 	{ smb_com_close,					/* 0x04 004 */
252 	    PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
253 	    RW_READER,
254 	    { "SmbClose", KSTAT_DATA_UINT64 } },
255 	{ smb_com_flush,					/* 0x05 005 */
256 	    PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
257 	    RW_READER,
258 	    { "SmbFlush", KSTAT_DATA_UINT64 } },
259 	{ smb_com_delete,					/* 0x06 006 */
260 	    PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
261 	    RW_READER,
262 	    { "SmbDelete", KSTAT_DATA_UINT64 } },
263 	{ smb_com_rename,					/* 0x07 007 */
264 	    PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
265 	    RW_READER,
266 	    { "SmbRename", KSTAT_DATA_UINT64 } },
267 	{ smb_com_query_information,				/* 0x08 008 */
268 	    PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
269 	    RW_READER,
270 	    { "SmbQueryInformation", KSTAT_DATA_UINT64 } },
271 	{ smb_com_set_information,				/* 0x09 009 */
272 	    PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
273 	    RW_READER,
274 	    { "SmbSetInformation", KSTAT_DATA_UINT64 } },
275 	{ smb_com_read,						/* 0x0A 010 */
276 	    PC_NETWORK_PROGRAM_1_0, SDDF_SUPPRESS_SHOW,
277 	    RW_READER,
278 	    { "SmbRead", KSTAT_DATA_UINT64 } },
279 	{ smb_com_write,					/* 0x0B 011 */
280 	    PC_NETWORK_PROGRAM_1_0, SDDF_SUPPRESS_SHOW,
281 	    RW_READER,
282 	    { "SmbWrite", KSTAT_DATA_UINT64 } },
283 	{ smb_com_lock_byte_range,				/* 0x0C 012 */
284 	    PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
285 	    RW_READER,
286 	    { "SmbLockByteRange", KSTAT_DATA_UINT64 } },
287 	{ smb_com_unlock_byte_range,				/* 0x0D 013 */
288 	    PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
289 	    RW_READER,
290 	    { "SmbUnlockByteRange", KSTAT_DATA_UINT64 } },
291 	{ smb_com_create_temporary,				/* 0x0E 014 */
292 	    PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
293 	    RW_READER,
294 	    { "SmbCreateTemporary", KSTAT_DATA_UINT64 } },
295 	{ smb_com_create_new,					/* 0x0F 015 */
296 	    PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
297 	    RW_READER,
298 	    { "SmbCreateNew",	KSTAT_DATA_UINT64 } },
299 	{ smb_com_check_directory,				/* 0x10 016 */
300 	    PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
301 	    RW_READER,
302 	    { "SmbCheckDirectory", KSTAT_DATA_UINT64 } },
303 	{ smb_com_process_exit,					/* 0x11 017 */
304 	    PC_NETWORK_PROGRAM_1_0, SDDF_SUPPRESS_TID | SDDF_SUPPRESS_UID,
305 	    RW_READER,
306 	    { "SmbProcessExit", KSTAT_DATA_UINT64 } },
307 	{ smb_com_seek,						/* 0x12 018 */
308 	    PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
309 	    RW_READER,
310 	    { "SmbSeek", KSTAT_DATA_UINT64 } },
311 	{ smb_com_lock_and_read,				/* 0x13 019 */
312 	    LANMAN1_0, SDDF_SUPPRESS_SHOW,
313 	    RW_READER,
314 	    { "SmbLockAndRead", KSTAT_DATA_UINT64 } },
315 	{ smb_com_write_and_unlock,				/* 0x14 020 */
316 	    LANMAN1_0, SDDF_SUPPRESS_SHOW,
317 	    RW_READER,
318 	    { "SmbWriteAndUnlock", KSTAT_DATA_UINT64 } },
319 	{ 0, 0, 0, RW_READER, 0 },				/* 0x15 021 */
320 	{ 0, 0, 0, RW_READER, 0 },				/* 0x16 022 */
321 	{ 0, 0, 0, RW_READER, 0 },				/* 0x17 023 */
322 	{ 0, 0, 0, RW_READER, 0 },				/* 0x18 024 */
323 	{ 0, 0, 0, RW_READER, 0 },				/* 0x19 025 */
324 	{ smb_com_read_raw,					/* 0x1A 026 */
325 	    LANMAN1_0, SDDF_SUPPRESS_SHOW,
326 	    RW_WRITER,
327 	    { "SmbReadRaw", KSTAT_DATA_UINT64 } },
328 	{ smb_com_read_mpx,					/* 0x1B 027 */
329 	    LANMAN1_0, SDDF_SUPPRESS_SHOW,
330 	    RW_READER,
331 	    { "SmbReadMpx", KSTAT_DATA_UINT64 } },
332 	{ smb_com_read_mpx_secondary,				/* 0x1C 028 */
333 	    LANMAN1_0, SDDF_SUPPRESS_SHOW,
334 	    RW_READER,
335 	    { "SmbReadMpxSecondary",	KSTAT_DATA_UINT64 } },
336 	{ smb_com_write_raw,					/* 0x1D 029 */
337 	    LANMAN1_0, SDDF_SUPPRESS_SHOW | SDDF_SUPPRESS_UNLEASH,
338 	    RW_WRITER,
339 	    { "SmbWriteRaw", KSTAT_DATA_UINT64 } },
340 	{ smb_com_write_mpx,					/* 0x1E 030 */
341 	    LANMAN1_0, SDDF_SUPPRESS_SHOW,
342 	    RW_READER,
343 	    { "SmbWriteMpx", KSTAT_DATA_UINT64 } },
344 	{ smb_com_write_mpx_secondary,				/* 0x1F 031 */
345 	    LANMAN1_0, SDDF_SUPPRESS_SHOW,
346 	    RW_READER,
347 	    { "SmbWriteMpxSecondary", KSTAT_DATA_UINT64 } },
348 	{ smb_com_write_complete,				/* 0x20 032 */
349 	    LANMAN1_0, SDDF_SUPPRESS_SHOW,
350 	    RW_READER,
351 	    { "SmbWriteComplete", KSTAT_DATA_UINT64 } },
352 	{ 0, 0, 0, 0, 0 },					/* 0x21 033 */
353 	{ smb_com_set_information2,				/* 0x22 034 */
354 	    LANMAN1_0, SDDF_NO_FLAGS,
355 	    RW_READER,
356 	    { "SmbSetInformation2", KSTAT_DATA_UINT64 } },
357 	{ smb_com_query_information2,				/* 0x23 035 */
358 	    LANMAN1_0, SDDF_NO_FLAGS,
359 	    RW_READER,
360 	    { "SmbQueryInformation2",	KSTAT_DATA_UINT64 } },
361 	{ smb_com_locking_andx,					/* 0x24 036 */
362 	    LANMAN1_0, SDDF_NO_FLAGS,
363 	    RW_READER,
364 	    { "SmbLockingX", KSTAT_DATA_UINT64 } },
365 	{ smb_com_transaction,					/* 0x25 037 */
366 	    LANMAN1_0, SDDF_NO_FLAGS,
367 	    RW_READER,
368 	    { "SmbTransaction", KSTAT_DATA_UINT64 } },
369 	{ smb_com_transaction_secondary,			/* 0x26 038 */
370 	    LANMAN1_0, SDDF_NO_FLAGS,
371 	    RW_READER,
372 	    { "SmbTransactionSecondary", KSTAT_DATA_UINT64 } },
373 	{ smb_com_ioctl,					/* 0x27 039 */
374 	    LANMAN1_0, SDDF_NO_FLAGS,
375 	    RW_READER,
376 	    { "SmbIoctl", KSTAT_DATA_UINT64 } },
377 	{ smb_com_ioctl_secondary,				/* 0x28 040 */
378 	    LANMAN1_0, SDDF_NO_FLAGS,
379 	    RW_READER,
380 	    { "SmbIoctlSecondary", KSTAT_DATA_UINT64 } },
381 	{ smb_com_copy,						/* 0x29 041 */
382 	    LANMAN1_0, SDDF_NO_FLAGS,
383 	    RW_READER,
384 	    { "SmbCopy", KSTAT_DATA_UINT64 } },
385 	{ smb_com_move,						/* 0x2A 042 */
386 	    LANMAN1_0, SDDF_NO_FLAGS,
387 	    RW_READER,
388 	    { "SmbMove", KSTAT_DATA_UINT64 } },
389 	{ smb_com_echo,						/* 0x2B 043 */
390 	    LANMAN1_0, SDDF_SUPPRESS_TID | SDDF_SUPPRESS_UID,
391 	    RW_READER,
392 	    { "SmbEcho", KSTAT_DATA_UINT64 } },
393 	{ smb_com_write_and_close,				/* 0x2C 044 */
394 	    LANMAN1_0, SDDF_SUPPRESS_SHOW,
395 	    RW_READER,
396 	    { "SmbWriteAndClose", KSTAT_DATA_UINT64 } },
397 	{ smb_com_open_andx,					/* 0x2D 045 */
398 	    LANMAN1_0, SDDF_NO_FLAGS,
399 	    RW_READER,
400 	    { "SmbOpenX", KSTAT_DATA_UINT64 } },
401 	{ smb_com_read_andx,					/* 0x2E 046 */
402 	    LANMAN1_0, SDDF_SUPPRESS_SHOW,
403 	    RW_READER,
404 	    { "SmbReadX", KSTAT_DATA_UINT64 } },
405 	{ smb_com_write_andx,					/* 0x2F 047 */
406 	    LANMAN1_0, SDDF_SUPPRESS_SHOW,
407 	    RW_READER,
408 	    { "SmbWriteX",	KSTAT_DATA_UINT64 } },
409 	{ 0, 0, 0, 0, 0 },					/* 0x30 048 */
410 	{ smb_com_close_and_tree_disconnect,			/* 0x31 049 */
411 	    LANMAN1_0, SDDF_NO_FLAGS,
412 	    RW_READER,
413 	    { "SmbCloseAndTreeDisconnect", KSTAT_DATA_UINT64 } },
414 	{ smb_com_transaction2,					/* 0x32 050 */
415 	    LM1_2X002, SDDF_NO_FLAGS,
416 	    RW_READER,
417 	    { "SmbTransaction2", KSTAT_DATA_UINT64 } },
418 	{ smb_com_transaction2_secondary,			/* 0x33 051 */
419 	    LM1_2X002, SDDF_NO_FLAGS,
420 	    RW_READER,
421 	    { "SmbTransaction2Secondary", KSTAT_DATA_UINT64 } },
422 	{ smb_com_find_close2,					/* 0x34 052 */
423 	    LM1_2X002, SDDF_NO_FLAGS,
424 	    RW_READER,
425 	    { "SmbFindClose2", KSTAT_DATA_UINT64 } },
426 	{ smb_com_find_notify_close,				/* 0x35 053 */
427 	    LM1_2X002, SDDF_NO_FLAGS,
428 	    RW_READER,
429 	    { "SmbFindNotifyClose", KSTAT_DATA_UINT64 } },
430 	{ 0, 0, 0, RW_READER, 0 },				/* 0x36 054 */
431 	{ 0, 0, 0, RW_READER, 0 },				/* 0x37 055 */
432 	{ 0, 0, 0, RW_READER, 0 },				/* 0x38 056 */
433 	{ 0, 0, 0, RW_READER, 0 },				/* 0x39 057 */
434 	{ 0, 0, 0, RW_READER, 0 },				/* 0x3A 058 */
435 	{ 0, 0, 0, RW_READER, 0 },				/* 0x3B 059 */
436 	{ 0, 0, 0, RW_READER, 0 },				/* 0x3C 060 */
437 	{ 0, 0, 0, RW_READER, 0 },				/* 0x3D 061 */
438 	{ 0, 0, 0, RW_READER, 0 },				/* 0x3E 062 */
439 	{ 0, 0, 0, RW_READER, 0 },				/* 0x3F 063 */
440 	{ 0, 0, 0, RW_READER, 0 },				/* 0x40 064 */
441 	{ 0, 0, 0, RW_READER, 0 },				/* 0x41 065 */
442 	{ 0, 0, 0, RW_READER, 0 },				/* 0x42 066 */
443 	{ 0, 0, 0, RW_READER, 0 },				/* 0x43 067 */
444 	{ 0, 0, 0, RW_READER, 0 },				/* 0x44 068 */
445 	{ 0, 0, 0, RW_READER, 0 },				/* 0x45 069 */
446 	{ 0, 0, 0, RW_READER, 0 },				/* 0x46 070 */
447 	{ 0, 0, 0, RW_READER, 0 },				/* 0x47 071 */
448 	{ 0, 0, 0, RW_READER, 0 },				/* 0x48 072 */
449 	{ 0, 0, 0, RW_READER, 0 },				/* 0x49 073 */
450 	{ 0, 0, 0, RW_READER, 0 },				/* 0x4A 074 */
451 	{ 0, 0, 0, RW_READER, 0 },				/* 0x4B 075 */
452 	{ 0, 0, 0, RW_READER, 0 },				/* 0x4C 076 */
453 	{ 0, 0, 0, RW_READER, 0 },				/* 0x4D 077 */
454 	{ 0, 0, 0, RW_READER, 0 },				/* 0x4E 078 */
455 	{ 0, 0, 0, RW_READER, 0 },				/* 0x4F 079 */
456 	{ 0, 0, 0, RW_READER, 0 },				/* 0x50 080 */
457 	{ 0, 0, 0, RW_READER, 0 },				/* 0x51 081 */
458 	{ 0, 0, 0, RW_READER, 0 },				/* 0x52 082 */
459 	{ 0, 0, 0, RW_READER, 0 },				/* 0x53 083 */
460 	{ 0, 0, 0, RW_READER, 0 },				/* 0x54 084 */
461 	{ 0, 0, 0, RW_READER, 0 },				/* 0x55 085 */
462 	{ 0, 0, 0, RW_READER, 0 },				/* 0x56 086 */
463 	{ 0, 0, 0, RW_READER, 0 },				/* 0x57 087 */
464 	{ 0, 0, 0, RW_READER, 0 },				/* 0x58 088 */
465 	{ 0, 0, 0, RW_READER, 0 },				/* 0x59 089 */
466 	{ 0, 0, 0, RW_READER, 0 },				/* 0x5A 090 */
467 	{ 0, 0, 0, RW_READER, 0 },				/* 0x5B 091 */
468 	{ 0, 0, 0, RW_READER, 0 },				/* 0x5C 092 */
469 	{ 0, 0, 0, RW_READER, 0 },				/* 0x5D 093 */
470 	{ 0, 0, 0, RW_READER, 0 },				/* 0x5E 094 */
471 	{ 0, 0, 0, RW_READER, 0 },				/* 0x5F 095 */
472 	{ 0, 0, 0, RW_READER, 0 },				/* 0x60 096 */
473 	{ 0, 0, 0, RW_READER, 0 },				/* 0x61 097 */
474 	{ 0, 0, 0, RW_READER, 0 },				/* 0x62 098 */
475 	{ 0, 0, 0, RW_READER, 0 },				/* 0x63 099 */
476 	{ 0, 0, 0, RW_READER, 0 },				/* 0x64 100 */
477 	{ 0, 0, 0, RW_READER, 0 },				/* 0x65 101 */
478 	{ 0, 0, 0, RW_READER, 0 },				/* 0x66 102 */
479 	{ 0, 0, 0, RW_READER, 0 },				/* 0x67 103 */
480 	{ 0, 0, 0, RW_READER, 0 },				/* 0x68 104 */
481 	{ 0, 0, 0, RW_READER, 0 },				/* 0x69 105 */
482 	{ 0, 0, 0, RW_READER, 0 },				/* 0x6A 106 */
483 	{ 0, 0, 0, RW_READER, 0 },				/* 0x6B 107 */
484 	{ 0, 0, 0, RW_READER, 0 },				/* 0x6C 108 */
485 	{ 0, 0, 0, RW_READER, 0 },				/* 0x6D 109 */
486 	{ 0, 0, 0, RW_READER, 0 },				/* 0x6E 110 */
487 	{ 0, 0, 0, RW_READER, 0 },				/* 0x6F 111 */
488 	{ smb_com_tree_connect,					/* 0x70 112 */
489 	    PC_NETWORK_PROGRAM_1_0, SDDF_SUPPRESS_TID,
490 	    RW_READER,
491 	    { "SmbTreeConnect", KSTAT_DATA_UINT64 } },
492 	{ smb_com_tree_disconnect,				/* 0x71 113 */
493 	    PC_NETWORK_PROGRAM_1_0, SDDF_SUPPRESS_TID | SDDF_SUPPRESS_UID,
494 	    RW_READER,
495 	    { "SmbTreeDisconnect", KSTAT_DATA_UINT64 } },
496 	{ smb_com_negotiate,					/* 0x72 114 */
497 	    PC_NETWORK_PROGRAM_1_0, SDDF_SUPPRESS_TID | SDDF_SUPPRESS_UID,
498 	    RW_WRITER,
499 	    { "SmbNegotiate", KSTAT_DATA_UINT64 } },
500 	{ smb_com_session_setup_andx,				/* 0x73 115 */
501 	    LANMAN1_0, SDDF_SUPPRESS_TID | SDDF_SUPPRESS_UID,
502 	    RW_READER,
503 	    { "SmbSessionSetupX",	KSTAT_DATA_UINT64 } },
504 	{ smb_com_logoff_andx,					/* 0x74 116 */
505 	    LM1_2X002, SDDF_SUPPRESS_TID,
506 	    RW_READER,
507 	    { "SmbLogoffX", KSTAT_DATA_UINT64 } },
508 	{ smb_com_tree_connect_andx,				/* 0x75 117 */
509 	    LANMAN1_0, SDDF_SUPPRESS_TID,
510 	    RW_READER,
511 	    { "SmbTreeConnectX", KSTAT_DATA_UINT64 } },
512 	{ 0, 0, 0, RW_READER, 0 },				/* 0x76 118 */
513 	{ 0, 0, 0, RW_READER, 0 },				/* 0x77 119 */
514 	{ 0, 0, 0, RW_READER, 0 },				/* 0x78 120 */
515 	{ 0, 0, 0, RW_READER, 0 },				/* 0x79 121 */
516 	{ 0, 0, 0, RW_READER, 0 },				/* 0x7A 122 */
517 	{ 0, 0, 0, RW_READER, 0 },				/* 0x7B 123 */
518 	{ 0, 0, 0, RW_READER, 0 },				/* 0x7C 124 */
519 	{ 0, 0, 0, RW_READER, 0 },				/* 0x7D 125 */
520 	{ 0, 0, 0, RW_READER, 0 },				/* 0x7E 126 */
521 	{ 0, 0, 0, RW_READER, 0 },				/* 0x7F 127 */
522 	{ smb_com_query_information_disk,			/* 0x80 128 */
523 	    PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
524 	    RW_READER,
525 	    { "SmbQueryInformationDisk", KSTAT_DATA_UINT64 } },
526 	{ smb_com_search,					/* 0x81 129 */
527 	    PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
528 	    RW_READER,
529 	    { "SmbSearch", KSTAT_DATA_UINT64 } },
530 	{ smb_com_find,						/* 0x82 130 */
531 	    LANMAN1_0, SDDF_NO_FLAGS,
532 	    RW_READER,
533 	    { "SmbFind", KSTAT_DATA_UINT64 } },
534 	{ smb_com_find_unique,					/* 0x83 131 */
535 	    LANMAN1_0, SDDF_NO_FLAGS,
536 	    RW_READER,
537 	    { "SmbFindUnique", KSTAT_DATA_UINT64 } },
538 	{ smb_com_find_close,					/* 0x84 132 */
539 	    LANMAN1_0, SDDF_NO_FLAGS,
540 	    RW_READER,
541 	    { "SmbFindClose", KSTAT_DATA_UINT64 } },
542 	{ 0, 0, 0, RW_READER, 0 },				/* 0x85 133 */
543 	{ 0, 0, 0, RW_READER, 0 },				/* 0x86 134 */
544 	{ 0, 0, 0, RW_READER, 0 },				/* 0x87 135 */
545 	{ 0, 0, 0, RW_READER, 0 },				/* 0x88 136 */
546 	{ 0, 0, 0, RW_READER, 0 },				/* 0x89 137 */
547 	{ 0, 0, 0, RW_READER, 0 },				/* 0x8A 138 */
548 	{ 0, 0, 0, RW_READER, 0 },				/* 0x8B 139 */
549 	{ 0, 0, 0, RW_READER, 0 },				/* 0x8C 140 */
550 	{ 0, 0, 0, RW_READER, 0 },				/* 0x8D 141 */
551 	{ 0, 0, 0, RW_READER, 0 },				/* 0x8E 142 */
552 	{ 0, 0, 0, RW_READER, 0 },				/* 0x8F 143 */
553 	{ 0, 0, 0, RW_READER, 0 },				/* 0x90 144 */
554 	{ 0, 0, 0, RW_READER, 0 },				/* 0x91 145 */
555 	{ 0, 0, 0, RW_READER, 0 },				/* 0x92 146 */
556 	{ 0, 0, 0, RW_READER, 0 },				/* 0x93 147 */
557 	{ 0, 0, 0, RW_READER, 0 },				/* 0x94 148 */
558 	{ 0, 0, 0, RW_READER, 0 },				/* 0x95 149 */
559 	{ 0, 0, 0, RW_READER, 0 },				/* 0x96 150 */
560 	{ 0, 0, 0, RW_READER, 0 },				/* 0x97 151 */
561 	{ 0, 0, 0, RW_READER, 0 },				/* 0x98 152 */
562 	{ 0, 0, 0, RW_READER, 0 },				/* 0x99 153 */
563 	{ 0, 0, 0, RW_READER, 0 },				/* 0x9A 154 */
564 	{ 0, 0, 0, RW_READER, 0 },				/* 0x9B 155 */
565 	{ 0, 0, 0, RW_READER, 0 },				/* 0x9C 156 */
566 	{ 0, 0, 0, RW_READER, 0 },				/* 0x9D 157 */
567 	{ 0, 0, 0, RW_READER, 0 },				/* 0x9E 158 */
568 	{ 0, 0, 0, RW_READER, 0 },				/* 0x9F 159 */
569 	{ smb_com_nt_transact,					/* 0xA0 160 */
570 	    NT_LM_0_12, SDDF_NO_FLAGS,
571 	    RW_READER,
572 	    { "SmbNtTransact",	KSTAT_DATA_UINT64 } },
573 	{ smb_com_nt_transact_secondary,			/* 0xA1 161 */
574 	    NT_LM_0_12, SDDF_NO_FLAGS,
575 	    RW_READER,
576 	    { "SmbNtTransactSecondary",	KSTAT_DATA_UINT64 } },
577 	{ smb_com_nt_create_andx,				/* 0xA2 162 */
578 	    NT_LM_0_12, SDDF_NO_FLAGS,
579 	    RW_READER,
580 	    { "SmbNtCreateX",	KSTAT_DATA_UINT64 } },
581 	{ 0, 0, 0, 0, 0 },					/* 0xA3 163 */
582 	{ smb_com_nt_cancel,					/* 0xA4 164 */
583 	    NT_LM_0_12, SDDF_NO_FLAGS,
584 	    RW_READER,
585 	    { "SmbNtCancel",	KSTAT_DATA_UINT64 } },
586 	{ 0, 0, 0, RW_READER, 0 },				/* 0xA5 165 */
587 	{ 0, 0, 0, RW_READER, 0 },				/* 0xA6 166 */
588 	{ 0, 0, 0, RW_READER, 0 },				/* 0xA7 167 */
589 	{ 0, 0, 0, RW_READER, 0 },				/* 0xA8 168 */
590 	{ 0, 0, 0, RW_READER, 0 },				/* 0xA9 169 */
591 	{ 0, 0, 0, RW_READER, 0 },				/* 0xAA 170 */
592 	{ 0, 0, 0, RW_READER, 0 },				/* 0xAB 171 */
593 	{ 0, 0, 0, RW_READER, 0 },				/* 0xAC 172 */
594 	{ 0, 0, 0, RW_READER, 0 },				/* 0xAD 173 */
595 	{ 0, 0, 0, RW_READER, 0 },				/* 0xAE 174 */
596 	{ 0, 0, 0, RW_READER, 0 },				/* 0xAF 175 */
597 	{ 0, 0, 0, RW_READER, 0 },				/* 0xB0 176 */
598 	{ 0, 0, 0, RW_READER, 0 },				/* 0xB1 177 */
599 	{ 0, 0, 0, RW_READER, 0 },				/* 0xB2 178 */
600 	{ 0, 0, 0, RW_READER, 0 },				/* 0xB3 179 */
601 	{ 0, 0, 0, RW_READER, 0 },				/* 0xB4 180 */
602 	{ 0, 0, 0, RW_READER, 0 },				/* 0xB5 181 */
603 	{ 0, 0, 0, RW_READER, 0 },				/* 0xB6 182 */
604 	{ 0, 0, 0, RW_READER, 0 },				/* 0xB7 183 */
605 	{ 0, 0, 0, RW_READER, 0 },				/* 0xB8 184 */
606 	{ 0, 0, 0, RW_READER, 0 },				/* 0xB9 185 */
607 	{ 0, 0, 0, RW_READER, 0 },				/* 0xBA 186 */
608 	{ 0, 0, 0, RW_READER, 0 },				/* 0xBB 187 */
609 	{ 0, 0, 0, RW_READER, 0 },				/* 0xBC 188 */
610 	{ 0, 0, 0, RW_READER, 0 },				/* 0xBD 189 */
611 	{ 0, 0, 0, RW_READER, 0 },				/* 0xBE 190 */
612 	{ 0, 0, 0, RW_READER, 0 },				/* 0xBF 191 */
613 	{ smb_com_open_print_file,				/* 0xC0 192 */
614 	    PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
615 	    RW_READER,
616 	    { "SmbOpenPrintFile", KSTAT_DATA_UINT64 } },
617 	{ smb_com_write_print_file,				/* 0xC1 193 */
618 	    PC_NETWORK_PROGRAM_1_0, SDDF_SUPPRESS_SHOW,
619 	    RW_READER,
620 	    { "SmbWritePrintFile", KSTAT_DATA_UINT64 } },
621 	{ smb_com_close_print_file,				/* 0xC2 194 */
622 	    PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
623 	    RW_READER,
624 	    { "SmbClosePrintFile", KSTAT_DATA_UINT64 } },
625 	{ smb_com_get_print_queue,				/* 0xC3 195 */
626 	    PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
627 	    RW_READER,
628 	    { "SmbGetPrintQueue", KSTAT_DATA_UINT64 } },
629 	{ 0, 0, 0, RW_READER, 0 },				/* 0xC4 196 */
630 	{ 0, 0, 0, RW_READER, 0 },				/* 0xC5 197 */
631 	{ 0, 0, 0, RW_READER, 0 },				/* 0xC6 198 */
632 	{ 0, 0, 0, RW_READER, 0 },				/* 0xC7 199 */
633 	{ 0, 0, 0, RW_READER, 0 },				/* 0xC8 200 */
634 	{ 0, 0, 0, RW_READER, 0 },				/* 0xC9 201 */
635 	{ 0, 0, 0, RW_READER, 0 },				/* 0xCA 202 */
636 	{ 0, 0, 0, RW_READER, 0 },				/* 0xCB 203 */
637 	{ 0, 0, 0, RW_READER, 0 },				/* 0xCC 204 */
638 	{ 0, 0, 0, RW_READER, 0 },				/* 0xCD 205 */
639 	{ 0, 0, 0, RW_READER, 0 },				/* 0xCE 206 */
640 	{ 0, 0, 0, RW_READER, 0 },				/* 0xCF 207 */
641 	{ smb_com_send_single_message,				/* 0xD0 208 */
642 	    PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
643 		RW_READER,
644 	    { "SmbSendSingleMessage", KSTAT_DATA_UINT64 } },
645 	{ smb_com_send_broadcast_message,			/* 0xD1 209 */
646 	    PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
647 	    RW_READER,
648 	    { "SmbSendBroadcastMessage", KSTAT_DATA_UINT64 } },
649 	{ smb_com_forward_user_name,				/* 0xD2 210 */
650 	    PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
651 	    RW_READER,
652 	    { "SmbForwardUserName", KSTAT_DATA_UINT64 } },
653 	{ smb_com_cancel_forward,				/* 0xD3 211 */
654 	    PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
655 	    RW_READER,
656 	    { "SmbCancelForward", KSTAT_DATA_UINT64 } },
657 	{ smb_com_get_machine_name,				/* 0xD4 212 */
658 	    PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
659 	    RW_READER,
660 	    { "SmbGetMachineName", KSTAT_DATA_UINT64 } },
661 	{ smb_com_send_start_mb_message,			/* 0xD5 213 */
662 	    PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
663 	    RW_READER,
664 	    { "SmbSendStartMbMessage", KSTAT_DATA_UINT64 } },
665 	{ smb_com_send_end_mb_message,				/* 0xD6 214 */
666 	    PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
667 	    RW_READER,
668 	    { "SmbSendEndMbMessage", KSTAT_DATA_UINT64 } },
669 	{ smb_com_send_text_mb_message,				/* 0xD7 215 */
670 	    PC_NETWORK_PROGRAM_1_0, SDDF_NO_FLAGS,
671 	    RW_READER,
672 	    { "SmbSendTextMbMessage", KSTAT_DATA_UINT64 } },
673 	{ 0, 0, 0, RW_READER, 0 },				/* 0xD8 216 */
674 	{ 0, 0, 0, RW_READER, 0 },				/* 0xD9 217 */
675 	{ 0, 0, 0, RW_READER, 0 },				/* 0xDA 218 */
676 	{ 0, 0, 0, RW_READER, 0 },				/* 0xDB 219 */
677 	{ 0, 0, 0, RW_READER, 0 },				/* 0xDC 220 */
678 	{ 0, 0, 0, RW_READER, 0 },				/* 0xDD 221 */
679 	{ 0, 0, 0, RW_READER, 0 },				/* 0xDE 222 */
680 	{ 0, 0, 0, RW_READER, 0 },				/* 0xDF 223 */
681 	{ 0, 0, 0, RW_READER, 0 },				/* 0xE0 224 */
682 	{ 0, 0, 0, RW_READER, 0 },				/* 0xE1 225 */
683 	{ 0, 0, 0, RW_READER, 0 },				/* 0xE2 226 */
684 	{ 0, 0, 0, RW_READER, 0 },				/* 0xE3 227 */
685 	{ 0, 0, 0, RW_READER, 0 },				/* 0xE4 228 */
686 	{ 0, 0, 0, RW_READER, 0 },				/* 0xE5 229 */
687 	{ 0, 0, 0, RW_READER, 0 },				/* 0xE6 230 */
688 	{ 0, 0, 0, RW_READER, 0 },				/* 0xE7 231 */
689 	{ 0, 0, 0, RW_READER, 0 },				/* 0xE8 232 */
690 	{ 0, 0, 0, RW_READER, 0 },				/* 0xE9 233 */
691 	{ 0, 0, 0, RW_READER, 0 },				/* 0xEA 234 */
692 	{ 0, 0, 0, RW_READER, 0 },				/* 0xEB 235 */
693 	{ 0, 0, 0, RW_READER, 0 },				/* 0xEC 236 */
694 	{ 0, 0, 0, RW_READER, 0 },				/* 0xED 237 */
695 	{ 0, 0, 0, RW_READER, 0 },				/* 0xEE 238 */
696 	{ 0, 0, 0, RW_READER, 0 },				/* 0xEF 239 */
697 	{ 0, 0, 0, RW_READER, 0 },				/* 0xF0 240 */
698 	{ 0, 0, 0, RW_READER, 0 },				/* 0xF1 241 */
699 	{ 0, 0, 0, RW_READER, 0 },				/* 0xF2 242 */
700 	{ 0, 0, 0, RW_READER, 0 },				/* 0xF3 243 */
701 	{ 0, 0, 0, RW_READER, 0 },				/* 0xF4 244 */
702 	{ 0, 0, 0, RW_READER, 0 },				/* 0xF5 245 */
703 	{ 0, 0, 0, RW_READER, 0 },				/* 0xF6 246 */
704 	{ 0, 0, 0, RW_READER, 0 },				/* 0xF7 247 */
705 	{ 0, 0, 0, RW_READER, 0 },				/* 0xF8 248 */
706 	{ 0, 0, 0, RW_READER, 0 },				/* 0xF9 249 */
707 	{ 0, 0, 0, RW_READER, 0 },				/* 0xFA 250 */
708 	{ 0, 0, 0, RW_READER, 0 },				/* 0xFB 251 */
709 	{ 0, 0, 0, RW_READER, 0 },				/* 0xFC 252 */
710 	{ 0, 0, 0, RW_READER, 0 },				/* 0xFD 253 */
711 	{ smb_com_invalid_command,				/* 0xFE 254 */
712 	    LANMAN1_0, SDDF_NO_FLAGS,
713 	    RW_READER,
714 	    { "SmbInvalidCommand", KSTAT_DATA_UINT64 } },
715 	{ 0, 0, 0, RW_READER, 0 }				/* 0xFF 255 */
716 };
717 
718 int smb_watch = -1;
719 int smb_emit_sending = 0;
720 
721 /*
722  * smbsr_cleanup
723  *
724  * If any user/tree/file is used by given request then
725  * the reference count for that resource has been incremented.
726  * This function decrements the reference count and close
727  * the resource if it's needed.
728  */
729 
730 void
731 smbsr_cleanup(struct smb_request *sr)
732 {
733 	ASSERT((sr->sr_state != SMB_REQ_STATE_CLEANED_UP) &&
734 	    (sr->sr_state != SMB_REQ_STATE_COMPLETED));
735 
736 	if (sr->fid_ofile)
737 		smbsr_disconnect_file(sr);
738 
739 	if (sr->sid_odir)
740 		smbsr_disconnect_dir(sr);
741 
742 	if (sr->tid_tree) {
743 		smb_tree_release(sr->tid_tree);
744 		sr->tid_tree = NULL;
745 	}
746 
747 	if (sr->uid_user) {
748 		smb_user_release(sr->uid_user);
749 		sr->uid_user = NULL;
750 	}
751 
752 	if (sr->r_xa) {
753 		if (sr->r_xa->xa_flags & SMB_XA_FLAG_COMPLETE)
754 			smb_xa_close(sr->r_xa);
755 		smb_xa_rele(sr->session, sr->r_xa);
756 		sr->r_xa = NULL;
757 	}
758 
759 	/*
760 	 * Mark this request so we know that we've already cleaned it up.
761 	 * A request should only get cleaned up once so multiple calls to
762 	 * smbsr_cleanup for the same request indicate a bug.
763 	 */
764 	mutex_enter(&sr->sr_mutex);
765 	if (sr->sr_state != SMB_REQ_STATE_CANCELED)
766 		sr->sr_state = SMB_REQ_STATE_CLEANED_UP;
767 	mutex_exit(&sr->sr_mutex);
768 }
769 
770 int
771 smb_dispatch_request(struct smb_request *sr)
772 {
773 	int			rc;
774 	smb_dispatch_table_t	*sdd;
775 	smb_error_t		err;
776 
777 	ASSERT(sr->tid_tree == 0);
778 	ASSERT(sr->uid_user == 0);
779 	ASSERT(sr->fid_ofile == 0);
780 	ASSERT(sr->sid_odir == 0);
781 	sr->smb_fid = (uint16_t)-1;
782 	sr->smb_sid = (uint16_t)-1;
783 
784 	/* temporary until we identify a user */
785 	sr->user_cr = kcred;
786 	sr->orig_request_hdr = sr->command.chain_offset;
787 
788 	/* If this connection is shutting down just kill request */
789 	if (smb_decode_mbc(&sr->command, SMB_HEADER_ED_FMT,
790 	    &sr->smb_com,
791 	    &sr->smb_rcls,
792 	    &sr->smb_reh,
793 	    &sr->smb_err,
794 	    &sr->smb_flg,
795 	    &sr->smb_flg2,
796 	    &sr->smb_pid_high,
797 	    sr->smb_sig,
798 	    &sr->smb_tid,
799 	    &sr->smb_pid,
800 	    &sr->smb_uid,
801 	    &sr->smb_mid) != 0) {
802 		return (-1);
803 	}
804 
805 	/*
806 	 * The reply "header" is filled in now even though
807 	 * it most likely will be rewritten under reply_ready:
808 	 * below. Could just reserve the space. But this
809 	 * (for now) is convenient incase the dialect dispatcher
810 	 * has to send a special reply (like TRANSACT).
811 	 *
812 	 * Ensure that the 32-bit error code flag is turned off.
813 	 * Clients seem to set it in transact requests and they may
814 	 * get confused if we return success or a 16-bit SMB code.
815 	 */
816 	sr->smb_rcls = 0;
817 	sr->smb_reh = 0;
818 	sr->smb_err = 0;
819 	sr->smb_flg2 &= ~SMB_FLAGS2_NT_STATUS;
820 
821 	(void) smb_encode_mbc(&sr->reply, SMB_HEADER_ED_FMT,
822 	    sr->smb_com,
823 	    sr->smb_rcls,
824 	    sr->smb_reh,
825 	    sr->smb_err,
826 	    sr->smb_flg,
827 	    sr->smb_flg2,
828 	    sr->smb_pid_high,
829 	    sr->smb_sig,
830 	    sr->smb_tid,
831 	    sr->smb_pid,
832 	    sr->smb_uid,
833 	    sr->smb_mid);
834 	sr->first_smb_com = sr->smb_com;
835 
836 	/*
837 	 * Verify SMB signature if signing is enabled, dialect is NT LM 0.12,
838 	 * signing was negotiated and authentication has occurred.
839 	 */
840 	if (sr->session->signing.flags & SMB_SIGNING_ENABLED) {
841 		if (smb_sign_check_request(sr) != 0) {
842 			err.severity = ERROR_SEVERITY_ERROR;
843 			err.status = NT_STATUS_ACCESS_DENIED;
844 			err.errcls = ERRDOS;
845 			err.errcode = ERROR_ACCESS_DENIED;
846 			smbsr_set_error(sr, &err);
847 			rc = -1;
848 			smb_rwx_rwenter(&sr->session->s_lock, RW_READER);
849 			goto reply_error;
850 		}
851 	}
852 
853 andx_more:
854 	sdd = &dispatch[sr->smb_com];
855 
856 	smb_rwx_rwenter(&sr->session->s_lock, sdd->sdt_slock_mode);
857 
858 	if (smb_decode_mbc(&sr->command, "b", &sr->smb_wct) != 0) {
859 		rc = -3;
860 		goto cant_decode;
861 	}
862 
863 	(void) MBC_SHADOW_CHAIN(&sr->smb_vwv, &sr->command,
864 	    sr->command.chain_offset, sr->smb_wct * 2);
865 
866 	if (smb_decode_mbc(&sr->command, "#.w",
867 	    sr->smb_wct*2, &sr->smb_bcc) != 0) {
868 		rc = -5;
869 		goto cant_decode;
870 	}
871 
872 	(void) MBC_SHADOW_CHAIN(&sr->smb_data, &sr->command,
873 	    sr->command.chain_offset, sr->smb_bcc);
874 
875 	sr->command.chain_offset += sr->smb_bcc;
876 	if (sr->command.chain_offset > sr->command.max_bytes) {
877 		rc = -6;
878 		goto cant_decode;
879 	}
880 
881 	/* Store pointers for later */
882 	sr->cur_reply_offset = sr->reply.chain_offset;
883 
884 	if (is_andx_com(sr->smb_com)) {
885 		/* Peek ahead and don't disturb vwv */
886 		if (smb_peek_mbc(&sr->smb_vwv, sr->smb_vwv.chain_offset, "b.w",
887 		    &sr->andx_com, &sr->andx_off) < 0) {
888 			rc = -7;
889 			goto cant_decode;
890 		}
891 	} else {
892 		sr->andx_com = (unsigned char)-1;
893 	}
894 
895 	mutex_enter(&sr->sr_mutex);
896 	switch (sr->sr_state) {
897 	case SMB_REQ_STATE_SUBMITTED:
898 	case SMB_REQ_STATE_CLEANED_UP:
899 		sr->sr_state = SMB_REQ_STATE_ACTIVE;
900 		break;
901 	case SMB_REQ_STATE_CANCELED:
902 		break;
903 	default:
904 		ASSERT(0);
905 		break;
906 	}
907 	mutex_exit(&sr->sr_mutex);
908 
909 	if (sdd->sdt_function) {
910 
911 		if ((rc = setjmp(&sr->exjb))) {
912 			/*
913 			 * Handle any errors from raw write.
914 			 */
915 			if (sr->session->s_state ==
916 			    SMB_SESSION_STATE_WRITE_RAW_ACTIVE) {
917 				/*
918 				 * Set state so that the netbios session
919 				 * daemon will start accepting data again.
920 				 */
921 				sr->session->s_write_raw_status = 0;
922 				sr->session->s_state =
923 				    SMB_SESSION_STATE_NEGOTIATED;
924 			}
925 
926 			/*
927 			 * We should never have sr->sr_keep set here
928 			 * since this is the error path.
929 			 */
930 			ASSERT(sr->sr_keep == 0);
931 
932 			smbsr_cleanup(sr);
933 
934 			if (sr->smb_com == smb_watch) {
935 				smb_emit_sending = 1;
936 			}
937 			if (rc < 0) {
938 				rc -= 1000;
939 				goto cant_decode;
940 			}
941 			goto reply_error;
942 		}
943 
944 		/*
945 		 * Setup UID and TID information (if required). Both functions
946 		 * will set the sr credentials. In domain mode, the user and
947 		 * tree credentials should be the same. In share mode, the
948 		 * tree credentials (defined in the share definition) should
949 		 * override the user credentials.
950 		 */
951 		if (!(sdd->sdt_flags & SDDF_SUPPRESS_UID)) {
952 			sr->uid_user = smb_user_lookup_by_uid(sr->session,
953 			    &sr->user_cr, sr->smb_uid);
954 			if (sr->uid_user == NULL) {
955 				smbsr_error(sr, 0, ERRSRV, ERRbaduid);
956 				/* NOTREACHED */
957 			}
958 			if (!(sdd->sdt_flags & SDDF_SUPPRESS_TID)) {
959 				sr->tid_tree = smb_tree_lookup_by_tid(
960 				    sr->uid_user, sr->smb_tid);
961 				if (sr->tid_tree == NULL) {
962 					smbsr_error(sr, 0, ERRSRV, ERRinvnid);
963 					/* NOTREACHED */
964 				}
965 			}
966 		}
967 
968 		/*
969 		 * If the command is not a read raw request we can set the
970 		 * state of the session back to SMB_SESSION_STATE_NEGOTIATED
971 		 * (if the current state is SMB_SESSION_STATE_OPLOCK_BREAKING).
972 		 * Otherwise we let the read raw handler to deal with it.
973 		 */
974 		if ((sr->session->s_state ==
975 		    SMB_SESSION_STATE_OPLOCK_BREAKING) &&
976 		    (sr->smb_com != SMB_COM_READ_RAW)) {
977 			krw_t	mode;
978 			/*
979 			 * The lock may have to be upgraded because, at this
980 			 * point, we don't know how it was entered. We just
981 			 * know that it has to be entered in writer mode here.
982 			 * Whatever mode was used to enter the lock, it will
983 			 * be restored.
984 			 */
985 			mode = smb_rwx_rwupgrade(&sr->session->s_lock);
986 			if (sr->session->s_state ==
987 			    SMB_SESSION_STATE_OPLOCK_BREAKING) {
988 				sr->session->s_state =
989 				    SMB_SESSION_STATE_NEGOTIATED;
990 			}
991 			smb_rwx_rwdowngrade(&sr->session->s_lock, mode);
992 		}
993 
994 		DTRACE_PROBE1(smb__dispatch__com, struct smb_request_t *, sr);
995 
996 		/*
997 		 * Increment method invocation count. This value is exposed
998 		 * via kstats, and it represents a count of all the dispatched
999 		 * requests, including the ones that have a return value, other
1000 		 * than SDRC_NORMAL_REPLY.
1001 		 */
1002 		SMB_ALL_DISPATCH_STAT_INCR(sdd->sdt_dispatch_stats.value.ui64);
1003 
1004 		rc = (*sdd->sdt_function)(sr);
1005 
1006 		/*
1007 		 * Only call smbsr_cleanup if smb->sr_keep is not set.  The
1008 		 * smb_nt_transact_notify_change function will set
1009 		 * smb->sr_keep if it retains control of the request when
1010 		 * it returns.  In that case the notify change code
1011 		 * will call smbsr_cleanup later when the request is finally
1012 		 * completed.
1013 		 */
1014 		if (sr->sr_keep == 0)
1015 			smbsr_cleanup(sr);
1016 	} else {
1017 		rc = SDRC_UNIMPLEMENTED;	/* Unknown? */
1018 	}
1019 
1020 	if (rc != SDRC_NORMAL_REPLY) {	/* normal case special & fast */
1021 		switch (rc) {
1022 		case SDRC_NORMAL_REPLY:
1023 			break;
1024 
1025 		case SDRC_ERROR_REPLY:
1026 			goto reply_error;
1027 
1028 		case SDRC_DROP_VC:
1029 			switch (sr->session->s_state) {
1030 			case SMB_SESSION_STATE_DISCONNECTED:
1031 			case SMB_SESSION_STATE_TERMINATED:
1032 				break;
1033 			default:
1034 				smb_soshutdown(sr->session->sock);
1035 				break;
1036 			}
1037 			goto reply_error;
1038 
1039 		case SDRC_NO_REPLY:
1040 			/* tricky. */
1041 			smb_rwx_rwexit(&sr->session->s_lock);
1042 			return (0);
1043 
1044 		case SDRC_UNIMPLEMENTED:
1045 			sr->smb_rcls = ERRDOS;
1046 			sr->smb_err = ERRbadfunc;
1047 			goto reply_error;
1048 
1049 		default:
1050 			sr->smb_rcls = ERRDOS;
1051 			sr->smb_err = ERRerror;	/* need better */
1052 			goto reply_error;
1053 		}
1054 	}
1055 
1056 	if (sr->andx_com == 0xff)
1057 		goto reply_ready;
1058 
1059 	/* have to back-patch the AndXCommand and AndXOffset */
1060 	sr->andx_prev_wct = sr->cur_reply_offset;
1061 	(void) smb_poke_mbc(&sr->reply, sr->andx_prev_wct + 1, "b.w",
1062 	    sr->andx_com, MBC_LENGTH(&sr->reply));
1063 
1064 	smb_rwx_rwexit(&sr->session->s_lock);
1065 
1066 	/* now it gets interesting */
1067 	sr->command.chain_offset = sr->orig_request_hdr + sr->andx_off;
1068 
1069 	sr->smb_com = sr->andx_com;
1070 
1071 	goto andx_more;
1072 
1073 reply_ready:
1074 
1075 	if (SMB_TREE_CASE_INSENSITIVE(sr)) {
1076 		sr->smb_flg |= SMB_FLAGS_CASE_INSENSITIVE;
1077 	} else {
1078 		sr->smb_flg &= ~SMB_FLAGS_CASE_INSENSITIVE;
1079 	}
1080 
1081 	(void) smb_poke_mbc(&sr->reply, 0, SMB_HEADER_ED_FMT,
1082 	    sr->first_smb_com,
1083 	    sr->smb_rcls,
1084 	    sr->smb_reh,
1085 	    sr->smb_err,
1086 	    sr->smb_flg | SMB_FLAGS_REPLY,
1087 	    sr->smb_flg2,
1088 	    sr->smb_pid_high,
1089 	    sr->smb_sig,
1090 	    sr->smb_tid,
1091 	    sr->smb_pid,
1092 	    sr->smb_uid,
1093 	    sr->smb_mid);
1094 
1095 	if (sr->session->signing.flags & SMB_SIGNING_ENABLED)
1096 		smb_sign_reply(sr, NULL);
1097 
1098 	if ((rc = smb_session_send(sr->session, 0, &sr->reply)) == 0)
1099 		sr->reply.chain = 0;
1100 
1101 	smb_rwx_rwexit(&sr->session->s_lock);
1102 
1103 	return (rc);
1104 
1105 cant_decode:
1106 reply_error:
1107 	sr->reply.chain_offset = sr->cur_reply_offset;
1108 	(void) smb_encode_mbc(&sr->reply, "bw", 0, 0);
1109 
1110 	sr->smb_wct = 0;
1111 	sr->smb_bcc = 0;
1112 
1113 	if (sr->smb_rcls == 0) {
1114 		sr->smb_rcls = ERRSRV;
1115 		sr->smb_err  = ERRerror;
1116 	}
1117 	goto reply_ready;
1118 }
1119 
1120 
1121 void
1122 smbsr_encode_result(struct smb_request *sr, int wct,
1123     int bcc, char *fmt, ...)
1124 {
1125 	va_list ap;
1126 
1127 	if (MBC_LENGTH(&sr->reply) != sr->cur_reply_offset) {
1128 		smbsr_encode_error(sr);
1129 	}
1130 
1131 	va_start(ap, fmt);
1132 	(void) smb_mbc_encode(&sr->reply, fmt, ap);
1133 	va_end(ap);
1134 
1135 	sr->smb_wct = (unsigned char)wct;
1136 	sr->smb_bcc = (uint16_t)bcc;
1137 
1138 	smbsr_check_result(sr, wct, bcc);
1139 }
1140 
1141 void
1142 smbsr_check_result(struct smb_request *sr, int wct, int bcc)
1143 {
1144 	int		offset = sr->cur_reply_offset;
1145 	int		total_bytes;
1146 	unsigned char	temp, temp1;
1147 	struct mbuf	*m;
1148 
1149 	total_bytes = 0;
1150 	m = sr->reply.chain;
1151 	while (m != 0) {
1152 		total_bytes += m->m_len;
1153 		m = m->m_next;
1154 	}
1155 
1156 	if ((offset + 3) > total_bytes) {
1157 		smbsr_encode_error(sr);
1158 		/* NOTREACHED */
1159 	}
1160 
1161 	(void) smb_peek_mbc(&sr->reply, offset, "b", &temp);
1162 	if (temp != wct) {
1163 		smbsr_encode_error(sr);
1164 		/* NOTREACHED */
1165 	}
1166 
1167 	if ((offset + (wct * 2 + 1)) > total_bytes) {
1168 		smbsr_encode_error(sr);
1169 		/* NOTREACHED */
1170 	}
1171 
1172 	/* reply wct & vwv seem ok, consider data now */
1173 	offset += wct * 2 + 1;
1174 
1175 	if ((offset + 2) > total_bytes) {
1176 		smbsr_encode_error(sr);
1177 	}
1178 
1179 	(void) smb_peek_mbc(&sr->reply, offset, "bb", &temp, &temp1);
1180 	if (bcc == VAR_BCC) {
1181 		if ((temp != 0xFF) || (temp1 != 0xFF)) {
1182 			smbsr_encode_error(sr);
1183 			/* NOTREACHED */
1184 		} else {
1185 			bcc = (total_bytes - offset) - 2;
1186 			(void) smb_poke_mbc(&sr->reply, offset, "bb",
1187 			    bcc, bcc >> 8);
1188 		}
1189 	} else {
1190 		if ((temp != (bcc&0xFF)) || (temp1 != ((bcc>>8)&0xFF))) {
1191 			smbsr_encode_error(sr);
1192 		}
1193 	}
1194 
1195 	offset += bcc + 2;
1196 
1197 	if (offset != total_bytes) {
1198 		smbsr_encode_error(sr);
1199 	}
1200 
1201 	sr->smb_wct = (unsigned char)wct;
1202 	sr->smb_bcc = (uint16_t)bcc;
1203 }
1204 
1205 int
1206 smbsr_decode_vwv(struct smb_request *sr, char *fmt, ...)
1207 {
1208 	int rc;
1209 	va_list ap;
1210 
1211 	va_start(ap, fmt);
1212 	rc = smb_mbc_decode(&sr->smb_vwv, fmt, ap);
1213 	va_end(ap);
1214 
1215 	return (rc);
1216 }
1217 
1218 int
1219 smbsr_decode_data(struct smb_request *sr, char *fmt, ...)
1220 {
1221 	int r;
1222 	va_list ap;
1223 	va_start(ap, fmt);
1224 	r = smb_mbc_decode(&sr->smb_data, fmt, ap);
1225 	va_end(ap);
1226 	return (r);
1227 }
1228 
1229 void
1230 smbsr_send_reply(struct smb_request *sr)
1231 {
1232 	(void) smb_poke_mbc(&sr->reply, 0, SMB_HEADER_ED_FMT,
1233 	    sr->first_smb_com,
1234 	    sr->smb_rcls,
1235 	    sr->smb_reh,
1236 	    sr->smb_err,
1237 	    sr->smb_flg | SMB_FLAGS_REPLY,
1238 	    sr->smb_flg2,
1239 	    sr->smb_pid_high,
1240 	    sr->smb_sig,
1241 	    sr->smb_tid,
1242 	    sr->smb_pid,
1243 	    sr->smb_uid,
1244 	    sr->smb_mid);
1245 
1246 	if (sr->session->signing.flags & SMB_SIGNING_ENABLED)
1247 		smb_sign_reply(sr, NULL);
1248 
1249 	(void) smb_session_send(sr->session, 0, &sr->reply);
1250 }
1251 
1252 
1253 void
1254 smbsr_decode_error(struct smb_request *sr)
1255 {
1256 	longjmp(&sr->exjb);
1257 }
1258 
1259 void
1260 smbsr_encode_error(struct smb_request *sr)
1261 {
1262 	longjmp(&sr->exjb);
1263 }
1264 
1265 void
1266 smbsr_encode_empty_result(struct smb_request *sr)
1267 {
1268 	smbsr_encode_result(sr, 0, 0, "bw", 0, 0);
1269 }
1270 
1271 /*
1272  * Map errno values to SMB and NT status values.
1273  * Note: ESRCH is a special case to handle a streams lookup failure.
1274  */
1275 static struct {
1276 	int errnum;
1277 	int errcls;
1278 	int errcode;
1279 	DWORD status32;
1280 } smb_errno_map[] = {
1281 	{ ENOSPC,	ERRDOS, ERROR_DISK_FULL, NT_STATUS_DISK_FULL },
1282 	{ EDQUOT,	ERRDOS, ERROR_DISK_FULL, NT_STATUS_DISK_FULL },
1283 	{ EPERM,	ERRSRV, ERRaccess, NT_STATUS_ACCESS_DENIED },
1284 	{ ENOTDIR,	ERRDOS, ERRbadpath, NT_STATUS_OBJECT_PATH_NOT_FOUND },
1285 	{ EISDIR,	ERRDOS, ERRbadpath, NT_STATUS_FILE_IS_A_DIRECTORY },
1286 	{ ENOENT,	ERRDOS, ERRbadfile, NT_STATUS_NO_SUCH_FILE },
1287 	{ ENOTEMPTY,	ERRDOS, ERROR_DIR_NOT_EMPTY,
1288 	    NT_STATUS_DIRECTORY_NOT_EMPTY },
1289 	{ EACCES,	ERRDOS, ERRnoaccess, NT_STATUS_ACCESS_DENIED },
1290 	{ ENOMEM,	ERRDOS, ERRnomem, NT_STATUS_NO_MEMORY },
1291 	{ EIO,		ERRHRD, ERRgeneral, NT_STATUS_IO_DEVICE_ERROR },
1292 	{ EXDEV, 	ERRSRV, ERRdiffdevice, NT_STATUS_NOT_SAME_DEVICE },
1293 	{ EROFS,	ERRHRD, ERRnowrite, NT_STATUS_ACCESS_DENIED },
1294 	{ ESTALE,	ERRDOS, ERRbadfid, NT_STATUS_INVALID_HANDLE},
1295 	{ EBADF,	ERRDOS, ERRbadfid, NT_STATUS_INVALID_HANDLE},
1296 	{ EEXIST,	ERRDOS, ERRfilexists, NT_STATUS_OBJECT_NAME_COLLISION},
1297 	{ ENXIO,	ERRSRV, ERRinvdevice, NT_STATUS_BAD_DEVICE_TYPE},
1298 	{ ESRCH,	ERRDOS, ERROR_FILE_NOT_FOUND,
1299 	    NT_STATUS_OBJECT_NAME_NOT_FOUND },
1300 	/*
1301 	 * It's not clear why smb_read_common effectively returns
1302 	 * ERRnoaccess if a range lock prevents access and smb_write_common
1303 	 * effectively returns ERRaccess.  This table entry is used by
1304 	 * smb_read_common and preserves the behavior that was there before.
1305 	 */
1306 	{ ERANGE,	ERRDOS, ERRnoaccess, NT_STATUS_FILE_LOCK_CONFLICT }
1307 };
1308 
1309 void
1310 smbsr_map_errno(int errnum, smb_error_t *err)
1311 {
1312 	int i;
1313 
1314 	for (i = 0; i < sizeof (smb_errno_map)/sizeof (smb_errno_map[0]); ++i) {
1315 		if (smb_errno_map[i].errnum == errnum) {
1316 			err->severity = ERROR_SEVERITY_ERROR;
1317 			err->status   = smb_errno_map[i].status32;
1318 			err->errcls   = smb_errno_map[i].errcls;
1319 			err->errcode  = smb_errno_map[i].errcode;
1320 			return;
1321 		}
1322 	}
1323 
1324 	err->severity = ERROR_SEVERITY_ERROR;
1325 	err->status   = NT_STATUS_INTERNAL_ERROR;
1326 	err->errcls   = ERRDOS;
1327 	err->errcode  = ERROR_INTERNAL_ERROR;
1328 }
1329 
1330 void
1331 smbsr_errno(struct smb_request *sr, int errnum)
1332 {
1333 	smb_error_t err;
1334 
1335 	smbsr_map_errno(errnum, &err);
1336 	smbsr_set_error(sr, &err);
1337 	longjmp(&sr->exjb);
1338 	/* NOTREACHED */
1339 }
1340 
1341 /*
1342  * Report a request processing warning.
1343  */
1344 void
1345 smbsr_warn(smb_request_t *sr, DWORD status, uint16_t errcls, uint16_t errcode)
1346 {
1347 	smb_error_t err;
1348 
1349 	err.severity = ERROR_SEVERITY_WARNING;
1350 	err.status   = status;
1351 	err.errcls   = errcls;
1352 	err.errcode  = errcode;
1353 
1354 	smbsr_set_error(sr, &err);
1355 }
1356 
1357 /*
1358  * Report a request processing error.  This function will not return.
1359  */
1360 void
1361 smbsr_error(smb_request_t *sr, DWORD status, uint16_t errcls, uint16_t errcode)
1362 {
1363 	smb_error_t err;
1364 
1365 	err.severity = ERROR_SEVERITY_ERROR;
1366 	err.status   = status;
1367 	err.errcls   = errcls;
1368 	err.errcode  = errcode;
1369 
1370 	smbsr_set_error(sr, &err);
1371 	longjmp(&sr->exjb);
1372 	/* NOTREACHED */
1373 }
1374 
1375 /*
1376  * Setup a request processing error.  This function can be used to
1377  * report 32-bit status codes or DOS errors.  Set the status code
1378  * to 0 (NT_STATUS_SUCCESS) to explicitly report a DOS error,
1379  * regardless of the client capabilities.
1380  *
1381  * If status is non-zero and the client supports 32-bit status
1382  * codes, report the status.  Otherwise, report the DOS error.
1383  */
1384 void
1385 smbsr_set_error(smb_request_t *sr, smb_error_t *err)
1386 {
1387 	uint32_t status;
1388 	uint32_t severity;
1389 	uint32_t capabilities;
1390 
1391 	ASSERT(sr);
1392 	ASSERT(err);
1393 
1394 	status = err->status;
1395 	severity = (err->severity == 0) ? ERROR_SEVERITY_ERROR : err->severity;
1396 	capabilities = sr->session->capabilities;
1397 
1398 	if ((err->errcls == 0) && (err->errcode == 0)) {
1399 		capabilities |= CAP_STATUS32;
1400 		if (status == 0)
1401 			status = NT_STATUS_INTERNAL_ERROR;
1402 	}
1403 
1404 	if ((capabilities & CAP_STATUS32) && (status != 0)) {
1405 		status |= severity;
1406 		sr->smb_rcls = status & 0xff;
1407 		sr->smb_reh = (status >> 8) & 0xff;
1408 		sr->smb_err  = status >> 16;
1409 		sr->smb_flg2 |= SMB_FLAGS2_NT_STATUS;
1410 	} else {
1411 		if ((err->errcls == 0) || (err->errcode == 0)) {
1412 			sr->smb_rcls = ERRSRV;
1413 			sr->smb_err  = ERRerror;
1414 		} else {
1415 			sr->smb_rcls = (uint8_t)err->errcls;
1416 			sr->smb_err  = (uint16_t)err->errcode;
1417 		}
1418 	}
1419 }
1420 
1421 smb_xa_t *
1422 smbsr_lookup_xa(smb_request_t *sr)
1423 {
1424 	ASSERT(sr->r_xa == 0);
1425 
1426 	sr->r_xa = smb_xa_find(sr->session, sr->smb_pid, sr->smb_mid);
1427 	return (sr->r_xa);
1428 }
1429 
1430 void
1431 smbsr_disconnect_file(smb_request_t *sr)
1432 {
1433 	smb_ofile_t	*of = sr->fid_ofile;
1434 
1435 	sr->fid_ofile = NULL;
1436 	(void) smb_ofile_release(of);
1437 }
1438 
1439 void
1440 smbsr_disconnect_dir(smb_request_t *sr)
1441 {
1442 	smb_odir_t	*od = sr->sid_odir;
1443 
1444 	sr->sid_odir = NULL;
1445 	smb_odir_release(od);
1446 }
1447 
1448 static int
1449 is_andx_com(unsigned char com)
1450 {
1451 	switch (com) {
1452 	case SMB_COM_LOCKING_ANDX:
1453 	case SMB_COM_OPEN_ANDX:
1454 	case SMB_COM_READ_ANDX:
1455 	case SMB_COM_WRITE_ANDX:
1456 	case SMB_COM_SESSION_SETUP_ANDX:
1457 	case SMB_COM_LOGOFF_ANDX:
1458 	case SMB_COM_TREE_CONNECT_ANDX:
1459 	case SMB_COM_NT_CREATE_ANDX:
1460 		return (1);
1461 	}
1462 	return (0);
1463 }
1464 
1465 /*
1466  * Invalid command stub.
1467  */
1468 /*ARGSUSED*/
1469 int
1470 smb_com_invalid_command(struct smb_request *sr)
1471 {
1472 	return (SDRC_UNIMPLEMENTED);
1473 }
1474 
1475 /*
1476  * smb_kstat_update_dispatch
1477  *
1478  * This callback function updates the smb_dispatch_kstat_data when kstat
1479  * command is invoked.
1480  */
1481 /*ARGSUSED*/
1482 static int
1483 smb_kstat_update_dispatch(kstat_t *ksp, int rw)
1484 {
1485 	int i = 0, j = 0;
1486 
1487 	if (rw == KSTAT_WRITE) {
1488 		return (EACCES);
1489 	} else {
1490 		for (i = 0; i < 256; i++) {
1491 			if (dispatch[i].sdt_function) {
1492 				(void) memcpy(&smb_dispatch_kstat_data[j],
1493 				    &(dispatch[i].sdt_dispatch_stats),
1494 				    sizeof (kstat_named_t));
1495 				j++;
1496 			}
1497 		}
1498 	}
1499 	return (0);
1500 }
1501 
1502 /*
1503  * smb_initialize_dispatch_kstat
1504  *
1505  * Initialize dispatch kstats.
1506  */
1507 void
1508 smb_initialize_dispatch_kstat()
1509 {
1510 	int i = 0, alloc_size = 0;
1511 
1512 	for (i = 0; i < 256; i++) {
1513 		if (dispatch[i].sdt_function)
1514 			smb_dispatch_kstat_size++;
1515 	}
1516 
1517 	alloc_size = smb_dispatch_kstat_size * sizeof (kstat_named_t);
1518 	smb_dispatch_kstat_data = (kstat_named_t *)
1519 	    kmem_zalloc(alloc_size, KM_SLEEP);
1520 
1521 	smb_dispatch_ksp = kstat_create("smb", 0, "smb_dispatch_all", "misc",
1522 	    KSTAT_TYPE_NAMED, alloc_size/sizeof (kstat_named_t),
1523 	    KSTAT_FLAG_VIRTUAL | KSTAT_FLAG_WRITABLE);
1524 	if (smb_dispatch_ksp) {
1525 		smb_dispatch_ksp->ks_data = smb_dispatch_kstat_data;
1526 		smb_dispatch_ksp->ks_update = smb_kstat_update_dispatch;
1527 		kstat_install(smb_dispatch_ksp);
1528 	}
1529 }
1530 
1531 /*
1532  * smb_remove_dispatch_kstat
1533  *
1534  * Remove dispatch kstats.
1535  */
1536 void
1537 smb_remove_dispatch_kstat()
1538 {
1539 	if (smb_dispatch_kstat_data != NULL)
1540 		kmem_free(smb_dispatch_kstat_data,
1541 		    smb_dispatch_kstat_size * sizeof (kstat_named_t));
1542 
1543 	if (smb_dispatch_ksp != NULL) {
1544 		kstat_delete(smb_dispatch_ksp);
1545 		smb_dispatch_ksp = NULL;
1546 	}
1547 }
1548