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