xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c (revision 07a6ae61f8958faa11352bf1b552d85d79e9cbbe)
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 2010 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  *
25  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
26  */
27 
28 /*
29  * SMB mbuf marshaling encode/decode.
30  */
31 
32 #include <smbsrv/smb_kproto.h>
33 
34 
35 #define	MALLOC_QUANTUM	80
36 
37 #define	DECODE_NO_ERROR		0
38 #define	DECODE_NO_MORE_DATA	1
39 #define	DECODE_ALLOCATION_ERROR	2
40 #define	DECODE_CONVERSION_ERROR	3
41 
42 static int mbc_marshal_make_room(mbuf_chain_t *, int32_t);
43 static void mbc_marshal_store_byte(mbuf_chain_t *, uint8_t);
44 static int mbc_marshal_put_char(mbuf_chain_t *mbc, uint8_t);
45 static int mbc_marshal_put_short(mbuf_chain_t *mbc, uint16_t);
46 static int mbc_marshal_put_long(mbuf_chain_t *mbc, uint32_t);
47 static int mbc_marshal_put_long_long(mbuf_chain_t *mbc, uint64_t);
48 static int mbc_marshal_put_oem_string(smb_request_t *, mbuf_chain_t *,
49     char *, int);
50 static int mbc_marshal_put_unicode_string(mbuf_chain_t *, char *, int);
51 static int mbc_marshal_put_uio(mbuf_chain_t *, struct uio *);
52 static int mbc_marshal_put_mbufs(mbuf_chain_t *mbc, mbuf_t *m);
53 static int mbc_marshal_put_mbuf_chain(mbuf_chain_t *mbc, mbuf_chain_t *nmbc);
54 static uint8_t mbc_marshal_fetch_byte(mbuf_chain_t *mbc);
55 static int mbc_marshal_get_char(mbuf_chain_t *mbc, uint8_t *data);
56 static int mbc_marshal_get_short(mbuf_chain_t *mbc, uint16_t *data);
57 static int mbc_marshal_get_long(mbuf_chain_t *mbc, uint32_t *data);
58 static uint64_t qswap(uint64_t ll);
59 static int mbc_marshal_get_odd_long_long(mbuf_chain_t *mbc, uint64_t *data);
60 static int mbc_marshal_get_long_long(mbuf_chain_t *mbc, uint64_t *data);
61 static int mbc_marshal_get_oem_string(smb_request_t *, mbuf_chain_t *,
62     char **, int);
63 static int mbc_marshal_get_unicode_string(smb_request_t *, mbuf_chain_t *,
64     char **, int);
65 static int mbc_marshal_get_mbufs(mbuf_chain_t *, int32_t, mbuf_t **);
66 static int mbc_marshal_get_mbuf_chain(mbuf_chain_t *, int32_t, mbuf_chain_t *);
67 static int mbc_marshal_get_uio(mbuf_chain_t *, struct uio *);
68 static int mbc_marshal_get_skip(mbuf_chain_t *, uint_t);
69 
70 /*
71  * smb_mbc_vdecodef
72  *
73  * This function reads the contents of the mbc chain passed in under the list
74  * of arguments passed in.
75  *
76  * The format string provides a description of the parameters passed in as well
77  * as an action to be taken by smb_mbc_vdecodef().
78  *
79  *	%	Pointer to an SMB request structure (smb_request_t *). There
80  *		should be only one of these in the string.
81  *
82  *	C	Pointer to an mbuf chain. Copy to that mbuf chain the number of
83  *		bytes specified (number preceding C).
84  *
85  *	m	Pointer to an mbuf. Copy to that mbuf the number of bytes
86  *		specified (number preceding m).
87  *
88  *	M	Read the 32 bit value at the current location of the mbuf chain
89  *		and check if it matches the signature of an SMB1 request (SMBx).
90  *
91  *	N	Read the 32 bit value at the current location of the mbuf chain
92  *		and check if it matches the signature of an SMB2 request (SMBx).
93  *
94  *	b	Pointer to a buffer. Copy to that buffer the number of bytes
95  *		specified (number preceding b).
96  *
97  *	c	Same as 'b'.
98  *
99  *	w	Pointer to a word (16bit value). Copy the next 16bit value into
100  *		that location.
101  *
102  *	l	Pointer to a long (32bit value). Copy the next 32bit value into
103  *		that location.
104  *
105  *	q	Pointer to a quad (64bit value). Copy the next 64bit value into
106  *		that location.
107  *
108  *	Q	Same as above with a call to qswap().
109  *
110  *	B	Pointer to a vardata_block structure. That structure is used to
111  *		retrieve data from the mbuf chain (an iovec type structure is
112  *		embedded in a vardata_block).
113  *
114  *	D	Pointer to a vardata_block structure. That structure is used to
115  *		retrieve data from the mbuf chain, however, two fields of the
116  *		vardata_block structure (tag and len) are first initialized
117  *		using the mbuf chain itself.
118  *
119  *	V	Same as 'D'.
120  *
121  *	L
122  *
123  *	A
124  *
125  *	P	Same as 'A'
126  *
127  *	S	Same as 'A'
128  *
129  *	u	Pointer to a string pointer. Allocate memory and retrieve the
130  *		string at the current location in the mbuf chain. Store the
131  *		address to the buffer allocated at the address specified by
132  *		the pointer. In addition if an sr was passed and it indicates
133  *		that the string is an unicode string, convert it.
134  *
135  *	s	Same as 'u' without convertion.
136  *
137  *	U	Same as 'u'. The string to retrieve is unicode.
138  *
139  *	y	Pointer to a 32bit value. Read the dos time at the current mbuf
140  *		chain location, convert it to unix time and store it at the
141  *		location indicated by the pointer.
142  *
143  *	Y	Same as 'y' bt the dos time coded in the mbuf chain is inverted.
144  *
145  *	.	Skip the number of bytes indicated by the number preceding '.'.
146  *
147  *	,	Same as '.' but take in account it is an unicode string.
148  */
149 int
150 smb_mbc_vdecodef(mbuf_chain_t *mbc, const char *fmt, va_list ap)
151 {
152 	uint8_t		c;
153 	uint8_t		cval;
154 	uint8_t		*cvalp;
155 	char		**charpp;
156 	uint16_t	wval;
157 	uint16_t	*wvalp;
158 	uint32_t	*lvalp;
159 	uint64_t	*llvalp;
160 	smb_vdb_t	*vdp;
161 	smb_request_t	*sr = NULL;
162 	uint32_t	lval;
163 	int		unicode = 0;
164 	int		repc;
165 	boolean_t	repc_specified;
166 
167 	while ((c = *fmt++) != 0) {
168 		repc_specified = B_FALSE;
169 		repc = 1;
170 
171 		if ('0' <= c && c <= '9') {
172 			repc = 0;
173 			do {
174 				repc = repc * 10 + c - '0';
175 				c = *fmt++;
176 			} while ('0' <= c && c <= '9');
177 			repc_specified = B_TRUE;
178 		} else if (c == '#') {
179 			repc = va_arg(ap, int);
180 			c = *fmt++;
181 			repc_specified = B_TRUE;
182 		}
183 
184 		switch (c) {
185 		case '%':
186 			sr = va_arg(ap, struct smb_request *);
187 			if (sr->session->dialect >= SMB_VERS_2_BASE) {
188 				unicode = 1;
189 				break;
190 			}
191 			unicode = sr->smb_flg2 & SMB_FLAGS2_UNICODE;
192 			break;
193 
194 		case 'C':	/* Mbuf_chain */
195 			if (mbc_marshal_get_mbuf_chain(mbc, repc,
196 			    va_arg(ap, mbuf_chain_t *)) != 0)
197 				return (-1);
198 			break;
199 
200 		case 'm':	/* struct_mbuf */
201 			if (mbc_marshal_get_mbufs(mbc, repc,
202 			    va_arg(ap, mbuf_t **)) != 0)
203 				return (-1);
204 			break;
205 
206 		case 'M':
207 			if (mbc_marshal_get_long(mbc, &lval) != 0)
208 				return (-1);
209 			if (lval != 0x424D53FF) /* 0xFF S M B */
210 				return (-1);
211 			break;
212 
213 		case 'N':
214 			if (mbc_marshal_get_long(mbc, &lval) != 0)
215 				return (-1);
216 			if (lval != 0x424D53FE) /* 0xFE S M B */
217 				return (-1);
218 			break;
219 
220 		case 'b':
221 		case 'c':
222 			cvalp = va_arg(ap, uint8_t *);
223 			if (MBC_ROOM_FOR(mbc, repc) == 0)
224 				/* Data will never be available */
225 				return (-1);
226 
227 			while (repc-- > 0)
228 				*cvalp++ = mbc_marshal_fetch_byte(mbc);
229 			break;
230 
231 		case 'w':
232 			wvalp = va_arg(ap, uint16_t *);
233 			while (repc-- > 0)
234 				if (mbc_marshal_get_short(mbc, wvalp++) != 0)
235 					return (-1);
236 			break;
237 
238 		case 'l':
239 			lvalp = va_arg(ap, uint32_t *);
240 			while (repc-- > 0)
241 				if (mbc_marshal_get_long(mbc, lvalp++) != 0)
242 					return (-1);
243 			break;
244 
245 		case 'q':
246 			llvalp = va_arg(ap, uint64_t *);
247 			while (repc-- > 0)
248 				if (mbc_marshal_get_long_long(
249 				    mbc, llvalp++) != 0)
250 					return (-1);
251 			break;
252 
253 		case 'Q':
254 			llvalp = va_arg(ap, uint64_t *);
255 			while (repc-- > 0)
256 				if (mbc_marshal_get_odd_long_long(
257 				    mbc, llvalp++) != 0)
258 					return (-1);
259 			break;
260 
261 		case 'B':
262 			vdp = va_arg(ap, struct vardata_block *);
263 			vdp->vdb_tag = 0;
264 			vdp->vdb_len = repc;
265 			vdp->vdb_uio.uio_iov = &vdp->vdb_iovec[0];
266 			vdp->vdb_uio.uio_iovcnt = MAX_IOVEC;
267 			vdp->vdb_uio.uio_extflg = UIO_COPY_DEFAULT;
268 			vdp->vdb_uio.uio_resid = repc;
269 			if (mbc_marshal_get_uio(mbc, &vdp->vdb_uio) != 0)
270 				return (-1);
271 			break;
272 
273 		case 'D':
274 		case 'V':
275 			vdp = va_arg(ap, struct vardata_block *);
276 			if (mbc_marshal_get_char(mbc, &vdp->vdb_tag) != 0)
277 				return (-1);
278 			if (mbc_marshal_get_short(mbc, &wval) != 0)
279 				return (-1);
280 			vdp->vdb_len = (uint32_t)wval;
281 			vdp->vdb_uio.uio_iov = &vdp->vdb_iovec[0];
282 			vdp->vdb_uio.uio_iovcnt = MAX_IOVEC;
283 			vdp->vdb_uio.uio_extflg = UIO_COPY_DEFAULT;
284 			vdp->vdb_uio.uio_resid = vdp->vdb_len;
285 			if (vdp->vdb_len != 0) {
286 				if (mbc_marshal_get_uio(mbc,
287 				    &vdp->vdb_uio) != 0)
288 					return (-1);
289 			}
290 			break;
291 
292 		case 'L':
293 			if (mbc_marshal_get_char(mbc, &cval) != 0)
294 				return (-1);
295 			if (cval != 2)
296 				return (-1);
297 			goto oem_conversion;
298 
299 		case 'A':
300 		case 'S':
301 			if (mbc_marshal_get_char(mbc, &cval) != 0)
302 				return (-1);
303 			if (((c == 'A' || c == 'S') && cval != 4) ||
304 			    (c == 'L' && cval != 2))
305 				return (-1);
306 			/* FALLTHROUGH */
307 
308 		case 'u': /* Convert from unicode if flags are set */
309 			if (unicode)
310 				goto unicode_translation;
311 			/* FALLTHROUGH */
312 
313 		case 's':	/* OEM string */
314 oem_conversion:
315 			ASSERT(sr != NULL);
316 			charpp = va_arg(ap, char **);
317 			if (!repc_specified)
318 				repc = 0;
319 			if (mbc_marshal_get_oem_string(sr,
320 			    mbc, charpp, repc) != 0)
321 				return (-1);
322 			break;
323 
324 		case 'U': /* Convert from unicode */
325 unicode_translation:
326 			ASSERT(sr != 0);
327 			charpp = va_arg(ap, char **);
328 			if (!repc_specified)
329 				repc = 0;
330 			if (mbc->chain_offset & 1)
331 				mbc->chain_offset++;
332 			if (mbc_marshal_get_unicode_string(sr,
333 			    mbc, charpp, repc) != 0)
334 				return (-1);
335 			break;
336 
337 		case 'Y': /* dos time to unix time tt/dd */
338 			lvalp = va_arg(ap, uint32_t *);
339 			while (repc-- > 0) {
340 				short	d, t;
341 
342 				if (mbc_marshal_get_short(mbc,
343 				    (uint16_t *)&t) != 0)
344 					return (-1);
345 				if (mbc_marshal_get_short(mbc,
346 				    (uint16_t *)&d) != 0)
347 					return (-1);
348 				*lvalp++ = smb_time_dos_to_unix(d, t);
349 			}
350 			break;
351 
352 		case 'y': /* dos time to unix time dd/tt */
353 			lvalp = va_arg(ap, uint32_t *);
354 			while (repc-- > 0) {
355 				short	d, t;
356 
357 				if (mbc_marshal_get_short(mbc,
358 				    (uint16_t *)&d) != 0)
359 					return (-1);
360 				if (mbc_marshal_get_short(mbc,
361 				    (uint16_t *)&t) != 0)
362 					return (-1);
363 				*lvalp++ = smb_time_dos_to_unix(d, t);
364 			}
365 			break;
366 
367 		case ',':
368 			if (unicode)
369 				repc *= 2;
370 			/* FALLTHROUGH */
371 
372 		case '.':
373 			if (mbc_marshal_get_skip(mbc, repc) != 0)
374 				return (-1);
375 			break;
376 
377 		default:
378 			ASSERT(0);
379 			return (-1);
380 		}
381 	}
382 	return (0);
383 }
384 
385 /*
386  * smb_mbc_decodef
387  *
388  * This function reads the contents of the mbc chain passed in under the
389  * control of the format fmt.
390  *
391  * (for a description of the format string see smb_mbc_vencodef()).
392  */
393 int
394 smb_mbc_decodef(mbuf_chain_t *mbc, const char *fmt, ...)
395 {
396 	int	xx;
397 	va_list	ap;
398 
399 	va_start(ap, fmt);
400 	xx = smb_mbc_vdecodef(mbc, fmt, ap);
401 	va_end(ap);
402 	return (xx);
403 }
404 
405 /*
406  * smb_mbc_peek
407  *
408  * This function reads the contents of the mbc passed in at the specified offset
409  * under the control of the format fmt. The offset of the chain passed in is not
410  * modified.
411  *
412  * (for a description of the format string see smb_mbc_vdecodef()).
413  */
414 int
415 smb_mbc_peek(mbuf_chain_t *mbc, int offset, const char *fmt, ...)
416 {
417 	mbuf_chain_t	tmp;
418 	va_list		ap;
419 	int		xx;
420 
421 	va_start(ap, fmt);
422 
423 	(void) MBC_SHADOW_CHAIN(&tmp, mbc, offset, mbc->max_bytes - offset);
424 	xx = smb_mbc_vdecodef(&tmp, fmt, ap);
425 	va_end(ap);
426 	return (xx);
427 }
428 
429 /*
430  * smb_mbc_vencodef
431  *
432  * This function builds a stream of bytes in the mbc chain passed in under the
433  * control of the list of arguments passed in.
434  *
435  * The format string provides a description of the parameters passed in as well
436  * as an action to be taken by smb_mbc_vencodef().
437  *
438  *	\b	Restore the mbuf chain offset to its initial value.
439  *
440  *	%	Pointer to an SMB request structure (smb_request_t *). There
441  *		should be only one of these in the string. If an sr in present
442  *		it will be used to determine if unicode conversion should be
443  *		applied to the strings.
444  *
445  *	C	Pointer to an mbuf chain. Copy that mbuf chain into the
446  *		destination mbuf chain.
447  *
448  *	D	Pointer to a vardata_block structure. Copy the data described
449  *		by that structure into the mbuf chain. The tag field is hard
450  *		coded to '1'.
451  *
452  *	M	Write the SMB1 request signature ('SMBX') into the mbuf chain.
453  *
454  *	N	Write the SMB2 request signature ('SMBX') into the mbuf chain.
455  *
456  *	T	Pointer to a timestruc_t. Convert the content of the structure
457  *		into NT time and store the result of the conversion in the
458  *		mbuf chain.
459  *
460  *	V	Same as 'D' but the tag field is hard coded to '5'.
461  *
462  *	b	Byte. Store the byte or the nymber of bytes specified into the
463  *		the mbuf chain. A format string like this "2b" would require 2
464  *		bytes to be passed in.
465  *
466  *	m	Pointer to an mbuf. Copy the contents of the mbuf into the mbuf
467  *		chain.
468  *
469  *	c	Pointer to a buffer. Copy the buffer into the mbuf chain. The
470  *		size of the buffer is indicated by the number preceding 'c'.
471  *
472  *	w	Word (16bit value). Store the word or the number of words
473  *              specified into the the mbuf chain. A format string like this
474  *		"2w" would require 2 words to be passed in.
475  *
476  *	l	Long (32bit value). Store the long or the number of longs
477  *		specified into the the mbuf chain. A format string like this
478  *		"2l" would require 2 longs to be passed in.
479  *
480  *	q	Quad (64bit value). Store the quad or the number of quads
481  *		specified into the the mbuf chain. A format string like this
482  *		"2q" would require 2 quads to be passed in.
483  *
484  *	L	Pointer to a string. Store the string passed in into the mbuf
485  *		chain preceded with a tag value of '2'.
486  *
487  *	S	Pointer to a string. Store the string passed in into the mbuf
488  *		chain preceded with a tag value of '4'. Applied a unicode
489  *		conversion is appropriate.
490  *
491  *	A	Same as 'S'
492  *
493  *	P	Pointer to a string. Store the string passed in into the mbuf
494  *		chain preceded with a tag value of '5'. Applied a unicode
495  *		conversion is appropriate.
496  *
497  *	u	Pointer to a string. Store the string passed in into the mbuf
498  *		chain. Applied a unicode conversion is appropriate.
499  *
500  *	s	Pointer to a string. Store the string passed in into the mbuf
501  *		chain.
502  *
503  *	Y	Date/Time.  Store the Date/Time or the number of Date/Time(s)
504  *		specified into the the mbuf chain. A format string like this
505  *		"2Y" would require 2 Date/Time values. The Date/Time is
506  *		converted to DOS before storing.
507  *
508  *	y	Same as 'Y'. The order of Date and Time is reversed.
509  *
510  *	,	Character. Store the character or number of character specified
511  *		into the mbuf chain.  A format string like this "2c" would
512  *		require 2 characters to be passed in. A unicode conversion is
513  *		applied if appropriate.
514  *
515  *	.	Same as '`' without unicode conversion.
516  *
517  *	U	Align the offset of the mbuf chain on a 16bit boundary.
518  */
519 int
520 smb_mbc_vencodef(mbuf_chain_t *mbc, const char *fmt, va_list ap)
521 {
522 	char 		*charp;
523 	uint8_t		*cvalp;
524 	timestruc_t	*tvp;
525 	smb_vdb_t	*vdp;
526 	smb_request_t	*sr = NULL;
527 	uint64_t	llval;
528 	int64_t		nt_time;
529 	uint32_t	lval;
530 	uint_t		tag;
531 	int		unicode = 0;
532 	int		repc;
533 	boolean_t	repc_specified;
534 	uint16_t	wval;
535 	uint8_t		cval;
536 	uint8_t		c;
537 
538 	while ((c = *fmt++) != 0) {
539 		repc_specified = B_FALSE;
540 		repc = 1;
541 
542 		if ('0' <= c && c <= '9') {
543 			repc = 0;
544 			do {
545 				repc = repc * 10 + c - '0';
546 				c = *fmt++;
547 			} while ('0' <= c && c <= '9');
548 			repc_specified = B_TRUE;
549 		} else if (c == '#') {
550 			repc = va_arg(ap, int);
551 			c = *fmt++;
552 			repc_specified = B_TRUE;
553 		}
554 
555 		switch (c) {
556 		case '%':
557 			sr = va_arg(ap, struct smb_request *);
558 			if (sr->session->dialect >= SMB_VERS_2_BASE) {
559 				unicode = 1;
560 				break;
561 			}
562 			unicode = sr->smb_flg2 & SMB_FLAGS2_UNICODE;
563 			break;
564 
565 		case 'C':	/* Mbuf_chain */
566 			if (mbc_marshal_put_mbuf_chain(mbc,
567 			    va_arg(ap, mbuf_chain_t *)) != 0)
568 				return (DECODE_NO_MORE_DATA);
569 			break;
570 
571 		case 'D':
572 			vdp = va_arg(ap, struct vardata_block *);
573 
574 			if (mbc_marshal_put_char(mbc, 1) != 0)
575 				return (DECODE_NO_MORE_DATA);
576 			if (mbc_marshal_put_short(mbc, vdp->vdb_len) != 0)
577 				return (DECODE_NO_MORE_DATA);
578 			if (mbc_marshal_put_uio(mbc, &vdp->vdb_uio) != 0)
579 				return (DECODE_NO_MORE_DATA);
580 			break;
581 
582 		case 'M':
583 			/* 0xFF S M B */
584 			if (mbc_marshal_put_long(mbc, 0x424D53FF))
585 				return (DECODE_NO_MORE_DATA);
586 			break;
587 
588 		case 'N':
589 			/* 0xFE S M B */
590 			if (mbc_marshal_put_long(mbc, 0x424D53FE))
591 				return (DECODE_NO_MORE_DATA);
592 			break;
593 
594 		case 'T':
595 			tvp = va_arg(ap, timestruc_t *);
596 			nt_time = smb_time_unix_to_nt(tvp);
597 			if (mbc_marshal_put_long_long(mbc, nt_time) != 0)
598 				return (DECODE_NO_MORE_DATA);
599 			break;
600 
601 		case 'V':
602 			vdp = va_arg(ap, struct vardata_block *);
603 
604 			if (mbc_marshal_put_char(mbc, 5) != 0)
605 				return (DECODE_NO_MORE_DATA);
606 			if (mbc_marshal_put_short(mbc, vdp->vdb_len) != 0)
607 				return (DECODE_NO_MORE_DATA);
608 			if (mbc_marshal_put_uio(mbc, &vdp->vdb_uio) != 0)
609 				return (DECODE_NO_MORE_DATA);
610 			break;
611 
612 		case 'b':
613 			while (repc-- > 0) {
614 				cval = va_arg(ap, int);
615 				if (mbc_marshal_put_char(mbc, cval) != 0)
616 					return (DECODE_NO_MORE_DATA);
617 			}
618 			break;
619 
620 		case 'm':	/* struct_mbuf */
621 			if (mbc_marshal_put_mbufs(mbc,
622 			    va_arg(ap, mbuf_t *)) != 0)
623 				return (DECODE_NO_MORE_DATA);
624 			break;
625 
626 		case 'c':
627 			cvalp = va_arg(ap, uint8_t *);
628 			while (repc-- > 0) {
629 				if (mbc_marshal_put_char(mbc,
630 				    *cvalp++) != 0)
631 					return (DECODE_NO_MORE_DATA);
632 			}
633 			break;
634 
635 		case 'w':
636 			while (repc-- > 0) {
637 				wval = va_arg(ap, int);
638 				if (mbc_marshal_put_short(mbc, wval) != 0)
639 					return (DECODE_NO_MORE_DATA);
640 			}
641 			break;
642 
643 		case 'l':
644 			while (repc-- > 0) {
645 				lval = va_arg(ap, uint32_t);
646 				if (mbc_marshal_put_long(mbc, lval) != 0)
647 					return (DECODE_NO_MORE_DATA);
648 			}
649 			break;
650 
651 		case 'q':
652 			while (repc-- > 0) {
653 				llval = va_arg(ap, uint64_t);
654 				if (mbc_marshal_put_long_long(mbc, llval) != 0)
655 					return (DECODE_NO_MORE_DATA);
656 			}
657 			break;
658 
659 
660 		case 'L':
661 			tag = 2;
662 			goto oem_conversion;
663 
664 		case 'S':
665 		case 'A':
666 			tag = 4;
667 			goto tagged_str;
668 
669 		case 'P':
670 			tag = 3;
671 			goto tagged_str;
672 
673 		tagged_str:
674 			if (mbc_marshal_put_char(mbc, tag) != 0)
675 				return (DECODE_NO_MORE_DATA);
676 			/* FALLTHROUGH */
677 
678 		case 'u':	/* Convert from unicode if flags are set */
679 			if (unicode)
680 				goto unicode_translation;
681 			/* FALLTHROUGH */
682 
683 		case 's':	/* OEM string */
684 oem_conversion:
685 			charp = va_arg(ap, char *);
686 			if (!repc_specified)
687 				repc = 0;
688 			if (mbc_marshal_put_oem_string(sr, mbc,
689 			    charp, repc) != 0)
690 				return (DECODE_NO_MORE_DATA);
691 			break;
692 
693 		case 'U': /* Convert to unicode, align to word boundary */
694 unicode_translation:
695 			if (mbc->chain_offset & 1)
696 				mbc->chain_offset++;
697 			charp = va_arg(ap, char *);
698 			if (!repc_specified)
699 				repc = 0;
700 			if (mbc_marshal_put_unicode_string(mbc,
701 			    charp, repc) != 0)
702 				return (DECODE_NO_MORE_DATA);
703 			break;
704 
705 		case 'Y':		/* int32_t, encode dos date/time */
706 			while (repc-- > 0) {
707 				uint16_t	d, t;
708 
709 				lval = va_arg(ap, uint32_t);
710 				smb_time_unix_to_dos(lval,
711 				    (short *)&d, (short *)&t);
712 				if (mbc_marshal_put_short(mbc, t) != 0)
713 					return (DECODE_NO_MORE_DATA);
714 				if (mbc_marshal_put_short(mbc, d) != 0)
715 					return (DECODE_NO_MORE_DATA);
716 			}
717 			break;
718 
719 		case 'y':		/* int32_t, encode dos date/time */
720 			while (repc-- > 0) {
721 				uint16_t	d, t;
722 
723 				lval = va_arg(ap, uint32_t);
724 				smb_time_unix_to_dos(lval,
725 				    (short *)&d, (short *)&t);
726 				if (mbc_marshal_put_short(mbc, d) != 0)
727 					return (DECODE_NO_MORE_DATA);
728 				if (mbc_marshal_put_short(mbc, t) != 0)
729 					return (DECODE_NO_MORE_DATA);
730 			}
731 			break;
732 
733 		case ',':
734 			if (unicode)
735 				repc *= 2;
736 			/* FALLTHROUGH */
737 
738 		case '.':
739 			while (repc-- > 0)
740 				if (mbc_marshal_put_char(mbc, 0) != 0)
741 					return (DECODE_NO_MORE_DATA);
742 			break;
743 
744 		default:
745 			ASSERT(0);
746 			return (-1);
747 		}
748 	}
749 	return (0);
750 }
751 
752 /*
753  * smb_mbc_encodef
754  *
755  * This function builds a stream of bytes in the mbc chain passed in under the
756  * control of the format fmt.
757  *
758  * (for a description of the format string see smb_mbc_vencodef()).
759  */
760 int
761 smb_mbc_encodef(mbuf_chain_t *mbc, const char *fmt, ...)
762 {
763 	int	rc;
764 	va_list	ap;
765 
766 	va_start(ap, fmt);
767 	rc = smb_mbc_vencodef(mbc, fmt, ap);
768 	va_end(ap);
769 	return (rc);
770 }
771 
772 /*
773  * smb_mbc_poke
774  *
775  * This function writes a stream of bytes in the mbc passed in at the specified
776  * offset under the control of the format fmt. The offset of the chain passed in
777  * is not modified.
778  *
779  * (for a description of the format string see smb_mbc_vencodef()).
780  */
781 int
782 smb_mbc_poke(mbuf_chain_t *mbc, int offset, const char *fmt, ...)
783 {
784 	int		len, rc;
785 	mbuf_chain_t	tmp;
786 	va_list		ap;
787 
788 	if ((len = mbc->max_bytes - offset) < 0)
789 		return (DECODE_NO_MORE_DATA);
790 	rc = MBC_SHADOW_CHAIN(&tmp, mbc, offset, len);
791 	if (rc)
792 		return (DECODE_NO_MORE_DATA);
793 
794 	va_start(ap, fmt);
795 	rc = smb_mbc_vencodef(&tmp, fmt, ap);
796 	va_end(ap);
797 
798 	return (rc);
799 }
800 
801 /*
802  * Copy data from the src mbuf chain to the dst mbuf chain,
803  * at the given offset in the src and current offset in dst,
804  * for copy_len bytes.  Does NOT update src->chain_offset.
805  */
806 int
807 smb_mbc_copy(mbuf_chain_t *dst_mbc, const mbuf_chain_t *src_mbc,
808 	int copy_offset, int copy_len)
809 {
810 	mbuf_t	*src_m;
811 	int offset, len;
812 	int rc;
813 
814 	if (copy_len <= 0)
815 		return (0);
816 	if (copy_offset < 0)
817 		return (EINVAL);
818 	if ((copy_offset + copy_len) > src_mbc->max_bytes)
819 		return (EMSGSIZE);
820 
821 	/*
822 	 * Advance to the src mbuf where we start copying.
823 	 */
824 	offset = copy_offset;
825 	src_m = src_mbc->chain;
826 	while (src_m && offset >= src_m->m_len) {
827 		offset -= src_m->m_len;
828 		src_m = src_m->m_next;
829 	}
830 	if (src_m == NULL)
831 		return (EFAULT);
832 
833 	/*
834 	 * Copy the first part, which may start somewhere past
835 	 * the beginning of the current mbuf.
836 	 */
837 	len = src_m->m_len - offset;
838 	if (len > copy_len)
839 		len = copy_len;
840 	rc = smb_mbc_put_mem(dst_mbc, src_m->m_data + offset, len);
841 	if (rc != 0)
842 		return (rc);
843 	copy_len -= len;
844 
845 	/*
846 	 * Copy remaining mbufs...
847 	 */
848 	while (copy_len > 0) {
849 		src_m = src_m->m_next;
850 		if (src_m == NULL)
851 			break;
852 		len = src_m->m_len;
853 		if (len > copy_len)
854 			len = copy_len;
855 		rc = smb_mbc_put_mem(dst_mbc, src_m->m_data, len);
856 		copy_len -= len;
857 	}
858 
859 	return (0);
860 }
861 
862 /*
863  * Copy data from the passed memory buffer into the mbuf chain
864  * at the current offset.
865  */
866 int
867 smb_mbc_put_mem(mbuf_chain_t *mbc, void *vmem, int mem_len)
868 {
869 	caddr_t mem = vmem;
870 	mbuf_t	*m;
871 	int32_t	offset, tlen;
872 	int rc;
873 
874 	if (mem_len <= 0)
875 		return (0);
876 
877 	if ((rc = mbc_marshal_make_room(mbc, mem_len)) != 0)
878 		return (rc);
879 
880 	/*
881 	 * Advance to the dst mbuf where we start copying.
882 	 * Allocations were done by _make_room().
883 	 */
884 	offset = mbc->chain_offset;
885 	m = mbc->chain;
886 	while (offset >= m->m_len) {
887 		ASSERT(m->m_len > 0);
888 		offset -= m->m_len;
889 		m = m->m_next;
890 	}
891 
892 	/*
893 	 * Copy the first part, which may start somewhere past
894 	 * the beginning of the current mbuf.
895 	 */
896 	tlen = m->m_len - offset;
897 	if (tlen > mem_len)
898 		tlen = mem_len;
899 	bcopy(mem, m->m_data + offset, tlen);
900 	mbc->chain_offset += tlen;
901 	mem += tlen;
902 	mem_len -= tlen;
903 
904 	/*
905 	 * Copy remaining mem into mbufs.  These all start
906 	 * at the beginning of each mbuf, and the last may
907 	 * end somewhere short of m_len.
908 	 */
909 	while (mem_len > 0) {
910 		m = m->m_next;
911 		tlen = m->m_len;
912 		if (tlen > mem_len)
913 			tlen = mem_len;
914 		bcopy(mem, m->m_data, tlen);
915 		mbc->chain_offset += tlen;
916 		mem += tlen;
917 		mem_len -= tlen;
918 	}
919 
920 	return (0);
921 }
922 
923 /*
924  * Put data into mbuf chain allocating as needed.
925  * Adds room to end of mbuf chain if needed.
926  */
927 static int
928 mbc_marshal_make_room(mbuf_chain_t *mbc, int32_t bytes_needed)
929 {
930 	mbuf_t	*m;
931 	mbuf_t	*l;
932 	int32_t	bytes_available;
933 
934 	bytes_needed += mbc->chain_offset;
935 	if (bytes_needed > mbc->max_bytes)
936 		return (EMSGSIZE);
937 
938 	if ((m = mbc->chain) == 0) {
939 		MGET(m, M_WAIT, MT_DATA);
940 		m->m_len = 0;
941 		MCLGET(m, M_WAIT);
942 		mbc->chain = m;
943 		/* xxxx */
944 		/* ^    */
945 	}
946 
947 	/* ---- ----- --xx ---xxx */
948 	/* ^			  */
949 
950 	l = 0;
951 	while ((m != 0) && (bytes_needed >= m->m_len)) {
952 		l = m;
953 		bytes_needed -= m->m_len;
954 		m = m->m_next;
955 	}
956 
957 	if ((bytes_needed == 0) || (m != 0)) {
958 		/* We have enough room already */
959 		return (0);
960 	}
961 
962 	/* ---- ----- --xx ---xxx */
963 	/*			 ^ */
964 	/* Back up to start of last mbuf */
965 	m = l;
966 	bytes_needed += m->m_len;
967 
968 	/* ---- ----- --xx ---xxx */
969 	/*		   ^	  */
970 
971 	bytes_available = (m->m_flags & M_EXT) ?
972 	    m->m_ext.ext_size : MLEN;
973 
974 	/* ---- ----- --xx ---xxx */
975 	/*		   ^	  */
976 	while ((bytes_needed != 0) && (bytes_needed > bytes_available)) {
977 		m->m_len = bytes_available;
978 		bytes_needed -= m->m_len;
979 		/* ---- ----- --xx ------ */
980 		/*		   ^	  */
981 
982 		MGET(m->m_next, M_WAIT, MT_DATA);
983 		m = m->m_next;
984 		m->m_len = 0;
985 		MCLGET(m, M_WAIT);
986 
987 		ASSERT((m->m_flags & M_EXT) != 0);
988 		bytes_available = m->m_ext.ext_size;
989 
990 		/* ---- ----- --xx ------ xxxx */
991 		/*			  ^    */
992 	}
993 
994 	/* ---- ----- --xx ------ xxxx */
995 	/*			  ^    */
996 	/* Expand last tail as needed */
997 	if (m->m_len <= bytes_needed) {
998 		m->m_len = bytes_needed;
999 		/* ---- ----- --xx ------ --xx */
1000 		/*			   ^   */
1001 	}
1002 
1003 	return (0);
1004 }
1005 
1006 static void
1007 mbc_marshal_store_byte(mbuf_chain_t *mbc, uint8_t data)
1008 {
1009 	mbuf_t	*m = mbc->chain;
1010 	int32_t	cur_offset = mbc->chain_offset;
1011 
1012 	/*
1013 	 * Scan forward looking for the last data currently in chain.
1014 	 */
1015 	while (cur_offset >= m->m_len) {
1016 		cur_offset -= m->m_len;
1017 		m = m->m_next;
1018 	}
1019 	((char *)m->m_data)[cur_offset] = data;
1020 	mbc->chain_offset++;
1021 }
1022 
1023 static int
1024 mbc_marshal_put_char(mbuf_chain_t *mbc, uint8_t data)
1025 {
1026 	if (mbc_marshal_make_room(mbc, sizeof (char)) != 0)
1027 		return (DECODE_NO_MORE_DATA);
1028 	mbc_marshal_store_byte(mbc, data);
1029 	return (0);
1030 }
1031 
1032 static int
1033 mbc_marshal_put_short(mbuf_chain_t *mbc, uint16_t data)
1034 {
1035 	if (mbc_marshal_make_room(mbc, sizeof (short)))
1036 		return (DECODE_NO_MORE_DATA);
1037 	mbc_marshal_store_byte(mbc, data);
1038 	mbc_marshal_store_byte(mbc, data >> 8);
1039 	return (0);
1040 }
1041 
1042 static int
1043 mbc_marshal_put_long(mbuf_chain_t *mbc, uint32_t data)
1044 {
1045 	if (mbc_marshal_make_room(mbc, sizeof (int32_t)))
1046 		return (DECODE_NO_MORE_DATA);
1047 	mbc_marshal_store_byte(mbc, data);
1048 	mbc_marshal_store_byte(mbc, data >> 8);
1049 	mbc_marshal_store_byte(mbc, data >> 16);
1050 	mbc_marshal_store_byte(mbc, data >> 24);
1051 	return (0);
1052 }
1053 
1054 static int
1055 mbc_marshal_put_long_long(mbuf_chain_t *mbc, uint64_t data)
1056 {
1057 	if (mbc_marshal_make_room(mbc, sizeof (int64_t)))
1058 		return (DECODE_NO_MORE_DATA);
1059 
1060 	mbc_marshal_store_byte(mbc, data);
1061 	mbc_marshal_store_byte(mbc, data >> 8);
1062 	mbc_marshal_store_byte(mbc, data >> 16);
1063 	mbc_marshal_store_byte(mbc, data >> 24);
1064 	mbc_marshal_store_byte(mbc, data >> 32);
1065 	mbc_marshal_store_byte(mbc, data >> 40);
1066 	mbc_marshal_store_byte(mbc, data >> 48);
1067 	mbc_marshal_store_byte(mbc, data >> 56);
1068 	return (0);
1069 }
1070 
1071 /*
1072  * Marshal a UTF-8 string (str) into mbc, converting to OEM codeset.
1073  * Also write a null unless the repc count limits the length we put.
1074  */
1075 static int
1076 mbc_marshal_put_oem_string(
1077     smb_request_t *sr,
1078     mbuf_chain_t *mbc,
1079     char *str,
1080     int repc)
1081 {
1082 	uint8_t		*s, *oembuf;
1083 	int		buflen;
1084 	int		oemlen;
1085 	int		putlen;
1086 
1087 	/*
1088 	 * First convert to OEM string.  The OEM string
1089 	 * will be no longer than the UTF-8 string.
1090 	 */
1091 	buflen = strlen(str) + 1;
1092 	oembuf = smb_srm_zalloc(sr, buflen);
1093 	oemlen = smb_mbstooem(oembuf, str, buflen);
1094 	if (oemlen == -1)
1095 		return (DECODE_NO_MORE_DATA);
1096 
1097 	/* null terminator */
1098 	if (oemlen < buflen)
1099 		oembuf[oemlen++] = '\0';
1100 
1101 	/* If specified, repc limits the length. */
1102 	putlen = oemlen;
1103 	if ((repc > 0) && (repc < putlen))
1104 		putlen = repc;
1105 
1106 	if (mbc_marshal_make_room(mbc, putlen))
1107 		return (DECODE_NO_MORE_DATA);
1108 
1109 	s = oembuf;
1110 	while (putlen > 0) {
1111 		mbc_marshal_store_byte(mbc, *s);
1112 		s++;
1113 		putlen--;
1114 	}
1115 
1116 	return (0);
1117 }
1118 
1119 /*
1120  * Marshal a UTF-8 string (str) into mbc, converting to UTF-16.
1121  * Also write a UTF-16 null (2 bytes) unless the repc count
1122  * limits the length we put into the mbc.
1123  */
1124 static int
1125 mbc_marshal_put_unicode_string(mbuf_chain_t *mbc, char *str, int repc)
1126 {
1127 	smb_wchar_t	wchar;
1128 	int		consumed;
1129 	int		length;
1130 
1131 	if ((length = smb_wcequiv_strlen(str)) == -1)
1132 		return (DECODE_NO_MORE_DATA);
1133 
1134 	/* null terminator */
1135 	length += sizeof (smb_wchar_t);
1136 
1137 	/* If specified, repc limits the length. */
1138 	if ((repc > 0) && (repc < length))
1139 		length = repc;
1140 
1141 	if (mbc_marshal_make_room(mbc, length))
1142 		return (DECODE_NO_MORE_DATA);
1143 	while (length > 0) {
1144 		consumed = smb_mbtowc(&wchar, str, MTS_MB_CHAR_MAX);
1145 		if (consumed == -1)
1146 			break;	/* Invalid sequence */
1147 		/*
1148 		 * Note that consumed will be 0 when the null terminator
1149 		 * is encountered and str will not be advanced beyond
1150 		 * that point. Length will continue to be decremented so
1151 		 * we won't get stuck here.
1152 		 */
1153 		str += consumed;
1154 		mbc_marshal_store_byte(mbc, wchar);
1155 		mbc_marshal_store_byte(mbc, wchar >> 8);
1156 		length -= sizeof (smb_wchar_t);
1157 	}
1158 	return (0);
1159 }
1160 
1161 static int /*ARGSUSED*/
1162 uiorefnoop(caddr_t p, int size, int adj)
1163 {
1164 	return (0);
1165 }
1166 
1167 static int
1168 mbc_marshal_put_uio(mbuf_chain_t *mbc, struct uio *uio)
1169 {
1170 	mbuf_t		**t;
1171 	mbuf_t		*m = NULL;
1172 	struct iovec	*iov = uio->uio_iov;
1173 	int32_t		i, iov_cnt = uio->uio_iovcnt;
1174 
1175 	iov = uio->uio_iov;
1176 	t = &mbc->chain;
1177 	for (i = 0; i < iov_cnt; i++) {
1178 		MGET(m, M_WAIT, MT_DATA);
1179 		m->m_ext.ext_buf = iov->iov_base;
1180 		m->m_ext.ext_ref = uiorefnoop;
1181 		m->m_data = m->m_ext.ext_buf;
1182 		m->m_flags |= M_EXT;
1183 		m->m_len = m->m_ext.ext_size = iov->iov_len;
1184 		mbc->max_bytes += m->m_len;
1185 		m->m_next = 0;
1186 		*t = m;
1187 		t = &m->m_next;
1188 		iov++;
1189 	}
1190 	return (0);
1191 }
1192 
1193 static int
1194 mbc_marshal_put_mbufs(mbuf_chain_t *mbc, mbuf_t *m)
1195 {
1196 	mbuf_t	*mt;
1197 	mbuf_t	**t;
1198 	int	bytes;
1199 
1200 	if (m != NULL) {
1201 		mt = m;
1202 		bytes = mt->m_len;
1203 		while (mt->m_next != 0) {
1204 			mt = mt->m_next;
1205 			bytes += mt->m_len;
1206 		}
1207 		if (bytes != 0) {
1208 			t = &mbc->chain;
1209 			while (*t != 0) {
1210 				bytes += (*t)->m_len;
1211 				t = &(*t)->m_next;
1212 			}
1213 			*t = m;
1214 			mbc->chain_offset = bytes;
1215 		} else {
1216 			m_freem(m);
1217 		}
1218 	}
1219 	return (0);
1220 }
1221 
1222 static int
1223 mbc_marshal_put_mbuf_chain(mbuf_chain_t *mbc, mbuf_chain_t *nmbc)
1224 {
1225 	if (nmbc->chain != 0) {
1226 		if (mbc_marshal_put_mbufs(mbc, nmbc->chain))
1227 			return (DECODE_NO_MORE_DATA);
1228 		MBC_SETUP(nmbc, nmbc->max_bytes);
1229 	}
1230 	return (0);
1231 }
1232 
1233 static uint8_t
1234 mbc_marshal_fetch_byte(mbuf_chain_t *mbc)
1235 {
1236 	uint8_t	data;
1237 	mbuf_t	*m = mbc->chain;
1238 	int32_t	offset = mbc->chain_offset;
1239 
1240 	while (offset >= m->m_len) {
1241 		offset -= m->m_len;
1242 		m = m->m_next;
1243 	}
1244 	data = ((uint8_t *)m->m_data)[offset];
1245 	mbc->chain_offset++;
1246 	return (data);
1247 }
1248 
1249 static int
1250 mbc_marshal_get_char(mbuf_chain_t *mbc, uint8_t *data)
1251 {
1252 	if (MBC_ROOM_FOR(mbc, sizeof (char)) == 0) {
1253 		/* Data will never be available */
1254 		return (DECODE_NO_MORE_DATA);
1255 	}
1256 	*data = mbc_marshal_fetch_byte(mbc);
1257 	return (0);
1258 }
1259 
1260 static int
1261 mbc_marshal_get_short(mbuf_chain_t *mbc, uint16_t *data)
1262 {
1263 	uint16_t	tmp;
1264 	mbuf_t		*m = mbc->chain;
1265 	int32_t		offset = mbc->chain_offset;
1266 
1267 	if (MBC_ROOM_FOR(mbc, sizeof (short)) == 0) {
1268 		/* Data will never be available */
1269 		return (DECODE_NO_MORE_DATA);
1270 	}
1271 
1272 	while (offset >= m->m_len) {
1273 		offset -= m->m_len;
1274 		m = m->m_next;
1275 	}
1276 	if ((m->m_len - offset) >= sizeof (short)) {
1277 		*data = LE_IN16(m->m_data + offset);
1278 		mbc->chain_offset += sizeof (short);
1279 	} else {
1280 		tmp = (uint16_t)mbc_marshal_fetch_byte(mbc);
1281 		tmp |= ((uint16_t)mbc_marshal_fetch_byte(mbc)) << 8;
1282 		*data = tmp;
1283 	}
1284 	return (0);
1285 }
1286 
1287 static int
1288 mbc_marshal_get_long(mbuf_chain_t *mbc, uint32_t *data)
1289 {
1290 	uint32_t	tmp;
1291 	mbuf_t		*m = mbc->chain;
1292 	int32_t		offset = mbc->chain_offset;
1293 
1294 	if (MBC_ROOM_FOR(mbc, sizeof (int32_t)) == 0) {
1295 		/* Data will never be available */
1296 		return (DECODE_NO_MORE_DATA);
1297 	}
1298 	while (offset >= m->m_len) {
1299 		offset -= m->m_len;
1300 		m = m->m_next;
1301 	}
1302 	if ((m->m_len - offset) >= sizeof (int32_t)) {
1303 		*data = LE_IN32(m->m_data + offset);
1304 		mbc->chain_offset += sizeof (int32_t);
1305 	} else {
1306 		tmp = (uint32_t)mbc_marshal_fetch_byte(mbc);
1307 		tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 8;
1308 		tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 16;
1309 		tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 24;
1310 		*data = tmp;
1311 	}
1312 	return (0);
1313 }
1314 
1315 static uint64_t
1316 qswap(uint64_t ll)
1317 {
1318 	uint64_t v;
1319 
1320 	v = ll >> 32;
1321 	v |= ll << 32;
1322 
1323 	return (v);
1324 }
1325 
1326 static int
1327 mbc_marshal_get_odd_long_long(mbuf_chain_t *mbc, uint64_t *data)
1328 {
1329 	uint64_t	tmp;
1330 	mbuf_t		*m = mbc->chain;
1331 	int32_t		offset = mbc->chain_offset;
1332 
1333 	if (MBC_ROOM_FOR(mbc, sizeof (int64_t)) == 0) {
1334 		/* Data will never be available */
1335 		return (DECODE_NO_MORE_DATA);
1336 	}
1337 	while (offset >= m->m_len) {
1338 		offset -= m->m_len;
1339 		m = m->m_next;
1340 	}
1341 
1342 	if ((m->m_len - offset) >= sizeof (int64_t)) {
1343 		*data = qswap(LE_IN64(m->m_data + offset));
1344 		mbc->chain_offset += sizeof (int64_t);
1345 	} else {
1346 		tmp = (uint64_t)mbc_marshal_fetch_byte(mbc) << 32;
1347 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 40;
1348 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 48;
1349 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 56;
1350 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc);
1351 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 8;
1352 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 16;
1353 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 24;
1354 
1355 		*(uint64_t *)data = tmp;
1356 	}
1357 	return (0);
1358 }
1359 
1360 static int
1361 mbc_marshal_get_long_long(mbuf_chain_t *mbc, uint64_t *data)
1362 {
1363 	uint64_t	tmp;
1364 	mbuf_t		*m = mbc->chain;
1365 	int32_t		offset = mbc->chain_offset;
1366 
1367 	if (MBC_ROOM_FOR(mbc, sizeof (int64_t)) == 0) {
1368 		/* Data will never be available */
1369 		return (DECODE_NO_MORE_DATA);
1370 	}
1371 	while (offset >= m->m_len) {
1372 		offset -= m->m_len;
1373 		m = m->m_next;
1374 	}
1375 	if ((m->m_len - offset) >= sizeof (int64_t)) {
1376 		*data = LE_IN64(m->m_data + offset);
1377 		mbc->chain_offset += sizeof (int64_t);
1378 	} else {
1379 		tmp = (uint32_t)mbc_marshal_fetch_byte(mbc);
1380 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 8;
1381 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 16;
1382 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 24;
1383 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 32;
1384 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 40;
1385 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 48;
1386 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 56;
1387 		*(uint64_t *)data = tmp;
1388 	}
1389 	return (0);
1390 }
1391 
1392 /*
1393  * mbc_marshal_get_oem_string
1394  *
1395  * Decode an OEM string, returning its UTF-8 form in strpp,
1396  * allocated using smb_srm_zalloc (automatically freed).
1397  * If repc != 0, consume no more than repc bytes.
1398  */
1399 static int
1400 mbc_marshal_get_oem_string(
1401     smb_request_t	*sr,
1402     mbuf_chain_t	*mbc,
1403     char		**strpp,
1404     int			repc)
1405 {
1406 	uint8_t		*ch, *rcvbuf;
1407 	char 		*mbsbuf;
1408 	int		mbslen, mbsmax;
1409 	int		buflen;
1410 	int		oemlen;
1411 
1412 	buflen = MALLOC_QUANTUM;
1413 	rcvbuf = smb_srm_zalloc(sr, buflen);
1414 
1415 	if (repc == 0)
1416 		repc = 0xffff;
1417 
1418 	oemlen = 0;
1419 	ch = rcvbuf;
1420 	for (;;) {
1421 		while (oemlen < buflen) {
1422 			if (repc-- <= 0) {
1423 				*ch++ = 0;
1424 				goto multibyte_encode;
1425 			}
1426 			if (MBC_ROOM_FOR(mbc, sizeof (char)) == 0) {
1427 				/* Data will never be available */
1428 				return (DECODE_NO_MORE_DATA);
1429 			}
1430 			if ((*ch++ = mbc_marshal_fetch_byte(mbc)) == 0)
1431 				goto multibyte_encode;
1432 			oemlen++;
1433 		}
1434 		buflen += MALLOC_QUANTUM;
1435 		rcvbuf = smb_srm_rezalloc(sr, rcvbuf, buflen);
1436 		ch = rcvbuf + oemlen;
1437 	}
1438 
1439 multibyte_encode:
1440 	/*
1441 	 * UTF-8 encode the return string for internal system use.
1442 	 * Allocated size is worst-case: 3x larger than OEM.
1443 	 */
1444 	mbsmax = (oemlen + 1) * MTS_MB_CHAR_MAX;
1445 	mbsbuf = smb_srm_zalloc(sr, mbsmax);
1446 	mbslen = smb_oemtombs(mbsbuf, rcvbuf, mbsmax);
1447 	if (mbslen == -1)
1448 		return (DECODE_NO_MORE_DATA);
1449 
1450 	*strpp = mbsbuf;
1451 	return (0);
1452 }
1453 
1454 /*
1455  * mbc_marshal_get_unicode_string
1456  *
1457  * Decode a UTF-16 string, returning its UTF-8 form in strpp,
1458  * allocated using smb_srm_zalloc (automatically freed).
1459  * If repc != 0, consume no more than repc bytes.
1460  */
1461 static int
1462 mbc_marshal_get_unicode_string(smb_request_t *sr,
1463     mbuf_chain_t *mbc, char **strpp, int repc)
1464 {
1465 	int		max;
1466 	uint16_t	wchar;
1467 	char		*ch;
1468 	int		emitted;
1469 	int		length = 0;
1470 
1471 	if (repc == 0)
1472 		repc = 0xffff;
1473 
1474 	max = MALLOC_QUANTUM;
1475 	*strpp = smb_srm_zalloc(sr, max);
1476 
1477 	ch = *strpp;
1478 	for (;;) {
1479 		while ((length + MTS_MB_CHAR_MAX) < max) {
1480 			if (repc <= 0)
1481 				goto done;
1482 			repc -= 2;
1483 
1484 			if (mbc_marshal_get_short(mbc, &wchar) != 0)
1485 				return (DECODE_NO_MORE_DATA);
1486 
1487 			if (wchar == 0)	goto done;
1488 
1489 			emitted = smb_wctomb(ch, wchar);
1490 			length += emitted;
1491 			ch += emitted;
1492 		}
1493 		max += MALLOC_QUANTUM;
1494 		*strpp = smb_srm_rezalloc(sr, *strpp, max);
1495 		ch = *strpp + length;
1496 	}
1497 done:	*ch = 0;
1498 	return (0);
1499 }
1500 
1501 static int /*ARGSUSED*/
1502 mbc_marshal_get_mbufs(mbuf_chain_t *mbc, int32_t bytes, mbuf_t **m)
1503 {
1504 	*m = NULL;
1505 	if (MBC_ROOM_FOR(mbc, bytes) == 0) {
1506 		/* Data will never be available */
1507 		return (DECODE_NO_MORE_DATA);
1508 	}
1509 	/* not yet implemented */
1510 	return (-1);
1511 }
1512 
1513 static int
1514 mbc_marshal_get_mbuf_chain(mbuf_chain_t *mbc, int32_t bytes, mbuf_chain_t *nmbc)
1515 {
1516 	int	rc;
1517 	mbuf_t	*m;
1518 
1519 	if (bytes == 0) {
1520 		/* Get all the rest */
1521 		bytes = mbc->max_bytes - mbc->chain_offset;
1522 	}
1523 
1524 	MBC_SETUP(nmbc, mbc->max_bytes);
1525 	if ((rc = mbc_marshal_get_mbufs(mbc, bytes, &m)) != 0) {
1526 		if (m)
1527 			m_freem(m);
1528 		return (rc);
1529 	}
1530 	nmbc->chain = m;
1531 	while (m != 0) {
1532 		bytes += m->m_len;
1533 		m = m->m_next;
1534 	}
1535 	nmbc->max_bytes = bytes;
1536 	return (0);
1537 }
1538 
1539 static int
1540 mbc_marshal_get_uio(mbuf_chain_t *mbc, struct uio *uio)
1541 {
1542 	int		i, offset;
1543 	int32_t		bytes = uio->uio_resid;
1544 	int32_t		remainder;
1545 	struct iovec	*iov;
1546 	mbuf_t		*m;
1547 
1548 	/*
1549 	 * The residual count is tested because in the case of write requests
1550 	 * with no data (smbtorture RAW-WRITE test will generate that type of
1551 	 * request) this function is called with a residual count of zero
1552 	 * bytes.
1553 	 */
1554 	if (bytes != 0) {
1555 		iov = uio->uio_iov;
1556 		uio->uio_segflg = UIO_SYSSPACE;
1557 		uio->uio_extflg = UIO_COPY_DEFAULT;
1558 
1559 		if (MBC_ROOM_FOR(mbc, bytes) == 0) {
1560 			/* Data will never be available */
1561 			return (DECODE_NO_MORE_DATA);
1562 		}
1563 
1564 		m = mbc->chain;
1565 		offset = mbc->chain_offset;
1566 		while (offset >= m->m_len) {
1567 			offset -= m->m_len;
1568 			m = m->m_next;
1569 			ASSERT((offset == 0) || (offset && m));
1570 		}
1571 
1572 		for (i = 0; (bytes > 0) && (i < uio->uio_iovcnt); i++) {
1573 			iov[i].iov_base = &m->m_data[offset];
1574 			remainder = m->m_len - offset;
1575 			if (remainder >= bytes) {
1576 				iov[i].iov_len = bytes;
1577 				mbc->chain_offset += bytes;
1578 				uio->uio_iovcnt = i + 1;
1579 				return (0);
1580 			}
1581 			iov[i].iov_len = remainder;
1582 			mbc->chain_offset += remainder;
1583 			bytes -= remainder;
1584 			m = m->m_next;
1585 			offset = 0;
1586 		}
1587 		return (DECODE_NO_MORE_DATA);
1588 	}
1589 	return (0);
1590 }
1591 
1592 static int
1593 mbc_marshal_get_skip(mbuf_chain_t *mbc, uint_t skip)
1594 {
1595 	if (MBC_ROOM_FOR(mbc, skip) == 0)
1596 		return (DECODE_NO_MORE_DATA);
1597 	mbc->chain_offset += skip;
1598 	return (0);
1599 }
1600