xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c (revision bd0ce624be4492bab2f6c53383a40618647aba28)
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_cstou8(char *, char *, size_t, char *, size_t);
43 static int mbc_marshal_make_room(mbuf_chain_t *, int32_t);
44 static void mbc_marshal_store_byte(mbuf_chain_t *, uint8_t);
45 static int mbc_marshal_put_char(mbuf_chain_t *mbc, uint8_t);
46 static int mbc_marshal_put_short(mbuf_chain_t *mbc, uint16_t);
47 static int mbc_marshal_put_long(mbuf_chain_t *mbc, uint32_t);
48 static int mbc_marshal_put_long_long(mbuf_chain_t *mbc, uint64_t);
49 static int mbc_marshal_put_ascii_string(mbuf_chain_t *, 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_ascii_string(smb_request_t *, mbuf_chain_t *,
62     uint8_t **ascii, int);
63 static int mbc_marshal_get_unicode_string(smb_request_t *, mbuf_chain_t *,
64     uint8_t **, 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 	uint8_t		**cvalpp;
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 ascii_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':
314 ascii_conversion:
315 			ASSERT(sr != NULL);
316 			cvalpp = va_arg(ap, uint8_t **);
317 			if (!repc_specified)
318 				repc = 0;
319 			if (mbc_marshal_get_ascii_string(sr,
320 			    mbc, cvalpp, repc) != 0)
321 				return (-1);
322 			break;
323 
324 		case 'U': /* Convert from unicode */
325 unicode_translation:
326 			ASSERT(sr != 0);
327 			cvalpp = va_arg(ap, uint8_t **);
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, cvalpp, 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 	uint8_t		*cvalp;
523 	timestruc_t	*tvp;
524 	smb_vdb_t	*vdp;
525 	smb_request_t	*sr = NULL;
526 	uint64_t	llval;
527 	int64_t		nt_time;
528 	uint32_t	lval;
529 	uint_t		tag;
530 	int		unicode = 0;
531 	int		repc;
532 	boolean_t	repc_specified;
533 	uint16_t	wval;
534 	uint8_t		cval;
535 	uint8_t		c;
536 
537 	while ((c = *fmt++) != 0) {
538 		repc_specified = B_FALSE;
539 		repc = 1;
540 
541 		if ('0' <= c && c <= '9') {
542 			repc = 0;
543 			do {
544 				repc = repc * 10 + c - '0';
545 				c = *fmt++;
546 			} while ('0' <= c && c <= '9');
547 			repc_specified = B_TRUE;
548 		} else if (c == '#') {
549 			repc = va_arg(ap, int);
550 			c = *fmt++;
551 			repc_specified = B_TRUE;
552 
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 ascii_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':	/* ASCII/multibyte string */
684 ascii_conversion:	cvalp = va_arg(ap, uint8_t *);
685 			if (!repc_specified)
686 				repc = 0;
687 			if (mbc_marshal_put_ascii_string(mbc,
688 			    (char *)cvalp, repc) != 0)
689 				return (DECODE_NO_MORE_DATA);
690 			break;
691 
692 		case 'Y':		/* int32_t, encode dos date/time */
693 			while (repc-- > 0) {
694 				uint16_t	d, t;
695 
696 				lval = va_arg(ap, uint32_t);
697 				smb_time_unix_to_dos(lval,
698 				    (short *)&d, (short *)&t);
699 				if (mbc_marshal_put_short(mbc, t) != 0)
700 					return (DECODE_NO_MORE_DATA);
701 				if (mbc_marshal_put_short(mbc, d) != 0)
702 					return (DECODE_NO_MORE_DATA);
703 			}
704 			break;
705 
706 		case 'y':		/* int32_t, encode dos date/time */
707 			while (repc-- > 0) {
708 				uint16_t	d, t;
709 
710 				lval = va_arg(ap, uint32_t);
711 				smb_time_unix_to_dos(lval,
712 				    (short *)&d, (short *)&t);
713 				if (mbc_marshal_put_short(mbc, d) != 0)
714 					return (DECODE_NO_MORE_DATA);
715 				if (mbc_marshal_put_short(mbc, t) != 0)
716 					return (DECODE_NO_MORE_DATA);
717 			}
718 			break;
719 
720 		case ',':
721 			if (unicode)
722 				repc *= 2;
723 			/* FALLTHROUGH */
724 
725 		case '.':
726 			while (repc-- > 0)
727 				if (mbc_marshal_put_char(mbc, 0) != 0)
728 					return (DECODE_NO_MORE_DATA);
729 			break;
730 
731 		case 'U': /* Convert to unicode, align to word boundary */
732 unicode_translation:
733 			if (mbc->chain_offset & 1)
734 				mbc->chain_offset++;
735 			cvalp = va_arg(ap, uint8_t *);
736 			if (!repc_specified)
737 				repc = 0;
738 			if (mbc_marshal_put_unicode_string(mbc,
739 			    (char *)cvalp, repc) != 0)
740 				return (DECODE_NO_MORE_DATA);
741 			break;
742 
743 		default:
744 			ASSERT(0);
745 			return (-1);
746 		}
747 	}
748 	return (0);
749 }
750 
751 /*
752  * smb_mbc_encodef
753  *
754  * This function builds a stream of bytes in the mbc chain passed in under the
755  * control of the format fmt.
756  *
757  * (for a description of the format string see smb_mbc_vencodef()).
758  */
759 int
760 smb_mbc_encodef(mbuf_chain_t *mbc, const char *fmt, ...)
761 {
762 	int	rc;
763 	va_list	ap;
764 
765 	va_start(ap, fmt);
766 	rc = smb_mbc_vencodef(mbc, fmt, ap);
767 	va_end(ap);
768 	return (rc);
769 }
770 
771 /*
772  * smb_mbc_poke
773  *
774  * This function writes a stream of bytes in the mbc passed in at the specified
775  * offset under the control of the format fmt. The offset of the chain passed in
776  * is not modified.
777  *
778  * (for a description of the format string see smb_mbc_vencodef()).
779  */
780 int
781 smb_mbc_poke(mbuf_chain_t *mbc, int offset, const char *fmt, ...)
782 {
783 	int		len, rc;
784 	mbuf_chain_t	tmp;
785 	va_list		ap;
786 
787 	if ((len = mbc->max_bytes - offset) < 0)
788 		return (DECODE_NO_MORE_DATA);
789 	rc = MBC_SHADOW_CHAIN(&tmp, mbc, offset, len);
790 	if (rc)
791 		return (DECODE_NO_MORE_DATA);
792 
793 	va_start(ap, fmt);
794 	rc = smb_mbc_vencodef(&tmp, fmt, ap);
795 	va_end(ap);
796 
797 	return (rc);
798 }
799 
800 /*
801  * Copy data from the src mbuf chain to the dst mbuf chain,
802  * at the given offset in the src and current offset in dst,
803  * for copy_len bytes.  Does NOT update src->chain_offset.
804  */
805 int
806 smb_mbc_copy(mbuf_chain_t *dst_mbc, const mbuf_chain_t *src_mbc,
807 	int copy_offset, int copy_len)
808 {
809 	mbuf_t	*src_m;
810 	int offset, len;
811 	int rc;
812 
813 	if (copy_len <= 0)
814 		return (0);
815 	if (copy_offset < 0)
816 		return (EINVAL);
817 	if ((copy_offset + copy_len) > src_mbc->max_bytes)
818 		return (EMSGSIZE);
819 
820 	/*
821 	 * Advance to the src mbuf where we start copying.
822 	 */
823 	offset = copy_offset;
824 	src_m = src_mbc->chain;
825 	while (src_m && offset >= src_m->m_len) {
826 		offset -= src_m->m_len;
827 		src_m = src_m->m_next;
828 	}
829 	if (src_m == NULL)
830 		return (EFAULT);
831 
832 	/*
833 	 * Copy the first part, which may start somewhere past
834 	 * the beginning of the current mbuf.
835 	 */
836 	len = src_m->m_len - offset;
837 	if (len > copy_len)
838 		len = copy_len;
839 	rc = smb_mbc_put_mem(dst_mbc, src_m->m_data + offset, len);
840 	if (rc != 0)
841 		return (rc);
842 	copy_len -= len;
843 
844 	/*
845 	 * Copy remaining mbufs...
846 	 */
847 	while (copy_len > 0) {
848 		src_m = src_m->m_next;
849 		if (src_m == NULL)
850 			break;
851 		len = src_m->m_len;
852 		if (len > copy_len)
853 			len = copy_len;
854 		rc = smb_mbc_put_mem(dst_mbc, src_m->m_data, len);
855 		copy_len -= len;
856 	}
857 
858 	return (0);
859 }
860 
861 /*
862  * Copy data from the passed memory buffer into the mbuf chain
863  * at the current offset.
864  */
865 int
866 smb_mbc_put_mem(mbuf_chain_t *mbc, void *vmem, int mem_len)
867 {
868 	caddr_t mem = vmem;
869 	mbuf_t	*m;
870 	int32_t	offset, tlen;
871 	int rc;
872 
873 	if (mem_len <= 0)
874 		return (0);
875 
876 	if ((rc = mbc_marshal_make_room(mbc, mem_len)) != 0)
877 		return (rc);
878 
879 	/*
880 	 * Advance to the dst mbuf where we start copying.
881 	 * Allocations were done by _make_room().
882 	 */
883 	offset = mbc->chain_offset;
884 	m = mbc->chain;
885 	while (offset >= m->m_len) {
886 		ASSERT(m->m_len > 0);
887 		offset -= m->m_len;
888 		m = m->m_next;
889 	}
890 
891 	/*
892 	 * Copy the first part, which may start somewhere past
893 	 * the beginning of the current mbuf.
894 	 */
895 	tlen = m->m_len - offset;
896 	if (tlen > mem_len)
897 		tlen = mem_len;
898 	bcopy(mem, m->m_data + offset, tlen);
899 	mbc->chain_offset += tlen;
900 	mem += tlen;
901 	mem_len -= tlen;
902 
903 	/*
904 	 * Copy remaining mem into mbufs.  These all start
905 	 * at the beginning of each mbuf, and the last may
906 	 * end somewhere short of m_len.
907 	 */
908 	while (mem_len > 0) {
909 		m = m->m_next;
910 		tlen = m->m_len;
911 		if (tlen > mem_len)
912 			tlen = mem_len;
913 		bcopy(mem, m->m_data, tlen);
914 		mbc->chain_offset += tlen;
915 		mem += tlen;
916 		mem_len -= tlen;
917 	}
918 
919 	return (0);
920 }
921 
922 /*
923  * Put data into mbuf chain allocating as needed.
924  * Adds room to end of mbuf chain if needed.
925  */
926 static int
927 mbc_marshal_make_room(mbuf_chain_t *mbc, int32_t bytes_needed)
928 {
929 	mbuf_t	*m;
930 	mbuf_t	*l;
931 	int32_t	bytes_available;
932 
933 	bytes_needed += mbc->chain_offset;
934 	if (bytes_needed > mbc->max_bytes)
935 		return (EMSGSIZE);
936 
937 	if ((m = mbc->chain) == 0) {
938 		MGET(m, M_WAIT, MT_DATA);
939 		m->m_len = 0;
940 		MCLGET(m, M_WAIT);
941 		mbc->chain = m;
942 		/* xxxx */
943 		/* ^    */
944 	}
945 
946 	/* ---- ----- --xx ---xxx */
947 	/* ^			  */
948 
949 	l = 0;
950 	while ((m != 0) && (bytes_needed >= m->m_len)) {
951 		l = m;
952 		bytes_needed -= m->m_len;
953 		m = m->m_next;
954 	}
955 
956 	if ((bytes_needed == 0) || (m != 0)) {
957 		/* We have enough room already */
958 		return (0);
959 	}
960 
961 	/* ---- ----- --xx ---xxx */
962 	/*			 ^ */
963 	/* Back up to start of last mbuf */
964 	m = l;
965 	bytes_needed += m->m_len;
966 
967 	/* ---- ----- --xx ---xxx */
968 	/*		   ^	  */
969 
970 	bytes_available = (m->m_flags & M_EXT) ?
971 	    m->m_ext.ext_size : MLEN;
972 
973 	/* ---- ----- --xx ---xxx */
974 	/*		   ^	  */
975 	while ((bytes_needed != 0) && (bytes_needed > bytes_available)) {
976 		m->m_len = bytes_available;
977 		bytes_needed -= m->m_len;
978 		/* ---- ----- --xx ------ */
979 		/*		   ^	  */
980 
981 		MGET(m->m_next, M_WAIT, MT_DATA);
982 		m = m->m_next;
983 		m->m_len = 0;
984 		MCLGET(m, M_WAIT);
985 
986 		ASSERT((m->m_flags & M_EXT) != 0);
987 		bytes_available = m->m_ext.ext_size;
988 
989 		/* ---- ----- --xx ------ xxxx */
990 		/*			  ^    */
991 	}
992 
993 	/* ---- ----- --xx ------ xxxx */
994 	/*			  ^    */
995 	/* Expand last tail as needed */
996 	if (m->m_len <= bytes_needed) {
997 		m->m_len = bytes_needed;
998 		/* ---- ----- --xx ------ --xx */
999 		/*			   ^   */
1000 	}
1001 
1002 	return (0);
1003 }
1004 
1005 static void
1006 mbc_marshal_store_byte(mbuf_chain_t *mbc, uint8_t data)
1007 {
1008 	mbuf_t	*m = mbc->chain;
1009 	int32_t	cur_offset = mbc->chain_offset;
1010 
1011 	/*
1012 	 * Scan forward looking for the last data currently in chain.
1013 	 */
1014 	while (cur_offset >= m->m_len) {
1015 		cur_offset -= m->m_len;
1016 		m = m->m_next;
1017 	}
1018 	((char *)m->m_data)[cur_offset] = data;
1019 	mbc->chain_offset++;
1020 }
1021 
1022 static int
1023 mbc_marshal_put_char(mbuf_chain_t *mbc, uint8_t data)
1024 {
1025 	if (mbc_marshal_make_room(mbc, sizeof (char)) != 0)
1026 		return (DECODE_NO_MORE_DATA);
1027 	mbc_marshal_store_byte(mbc, data);
1028 	return (0);
1029 }
1030 
1031 static int
1032 mbc_marshal_put_short(mbuf_chain_t *mbc, uint16_t data)
1033 {
1034 	if (mbc_marshal_make_room(mbc, sizeof (short)))
1035 		return (DECODE_NO_MORE_DATA);
1036 	mbc_marshal_store_byte(mbc, data);
1037 	mbc_marshal_store_byte(mbc, data >> 8);
1038 	return (0);
1039 }
1040 
1041 static int
1042 mbc_marshal_put_long(mbuf_chain_t *mbc, uint32_t data)
1043 {
1044 	if (mbc_marshal_make_room(mbc, sizeof (int32_t)))
1045 		return (DECODE_NO_MORE_DATA);
1046 	mbc_marshal_store_byte(mbc, data);
1047 	mbc_marshal_store_byte(mbc, data >> 8);
1048 	mbc_marshal_store_byte(mbc, data >> 16);
1049 	mbc_marshal_store_byte(mbc, data >> 24);
1050 	return (0);
1051 }
1052 
1053 static int
1054 mbc_marshal_put_long_long(mbuf_chain_t *mbc, uint64_t data)
1055 {
1056 	if (mbc_marshal_make_room(mbc, sizeof (int64_t)))
1057 		return (DECODE_NO_MORE_DATA);
1058 
1059 	mbc_marshal_store_byte(mbc, data);
1060 	mbc_marshal_store_byte(mbc, data >> 8);
1061 	mbc_marshal_store_byte(mbc, data >> 16);
1062 	mbc_marshal_store_byte(mbc, data >> 24);
1063 	mbc_marshal_store_byte(mbc, data >> 32);
1064 	mbc_marshal_store_byte(mbc, data >> 40);
1065 	mbc_marshal_store_byte(mbc, data >> 48);
1066 	mbc_marshal_store_byte(mbc, data >> 56);
1067 	return (0);
1068 }
1069 
1070 /*
1071  * When need to convert from UTF-8 (internal format) to a single
1072  * byte string (external format ) when marshalling a string.
1073  */
1074 static int
1075 mbc_marshal_put_ascii_string(mbuf_chain_t *mbc, char *mbs, int repc)
1076 {
1077 	smb_wchar_t	wide_char;
1078 	int		nbytes;
1079 	int		length;
1080 
1081 	if ((length = smb_sbequiv_strlen(mbs)) == -1)
1082 		return (DECODE_NO_MORE_DATA);
1083 
1084 	length += sizeof (char);
1085 
1086 	if ((repc > 0) && (repc < length))
1087 		length = repc;
1088 	if (mbc_marshal_make_room(mbc, length))
1089 		return (DECODE_NO_MORE_DATA);
1090 
1091 	while (*mbs) {
1092 		/*
1093 		 * We should restore oem chars here.
1094 		 */
1095 		nbytes = smb_mbtowc(&wide_char, mbs, MTS_MB_CHAR_MAX);
1096 		if (nbytes == -1)
1097 			return (DECODE_NO_MORE_DATA);
1098 
1099 		mbc_marshal_store_byte(mbc, (uint8_t)wide_char);
1100 
1101 		if (wide_char & 0xFF00)
1102 			mbc_marshal_store_byte(mbc, wide_char >> 8);
1103 
1104 		mbs += nbytes;
1105 	}
1106 
1107 	mbc_marshal_store_byte(mbc, 0);
1108 	return (0);
1109 }
1110 
1111 static int
1112 mbc_marshal_put_unicode_string(mbuf_chain_t *mbc, char *ascii, int repc)
1113 {
1114 	smb_wchar_t	wchar;
1115 	int		consumed;
1116 	int		length;
1117 
1118 	if ((length = smb_wcequiv_strlen(ascii)) == -1)
1119 		return (DECODE_NO_MORE_DATA);
1120 
1121 	length += sizeof (smb_wchar_t);
1122 
1123 	if ((repc > 0) && (repc < length))
1124 		length = repc;
1125 
1126 	if (mbc_marshal_make_room(mbc, length))
1127 		return (DECODE_NO_MORE_DATA);
1128 	while (length > 0) {
1129 		consumed = smb_mbtowc(&wchar, ascii, MTS_MB_CHAR_MAX);
1130 		if (consumed == -1)
1131 			break;	/* Invalid sequence */
1132 		/*
1133 		 * Note that consumed will be 0 when the null terminator
1134 		 * is encountered and ascii will not be advanced beyond
1135 		 * that point. Length will continue to be decremented so
1136 		 * we won't get stuck here.
1137 		 */
1138 		ascii += consumed;
1139 		mbc_marshal_store_byte(mbc, wchar);
1140 		mbc_marshal_store_byte(mbc, wchar >> 8);
1141 		length -= sizeof (smb_wchar_t);
1142 	}
1143 	return (0);
1144 }
1145 
1146 static int /*ARGSUSED*/
1147 uiorefnoop(caddr_t p, int size, int adj)
1148 {
1149 	return (0);
1150 }
1151 
1152 static int
1153 mbc_marshal_put_uio(mbuf_chain_t *mbc, struct uio *uio)
1154 {
1155 	mbuf_t		**t;
1156 	mbuf_t		*m = NULL;
1157 	struct iovec	*iov = uio->uio_iov;
1158 	int32_t		i, iov_cnt = uio->uio_iovcnt;
1159 
1160 	iov = uio->uio_iov;
1161 	t = &mbc->chain;
1162 	for (i = 0; i < iov_cnt; i++) {
1163 		MGET(m, M_WAIT, MT_DATA);
1164 		m->m_ext.ext_buf = iov->iov_base;
1165 		m->m_ext.ext_ref = uiorefnoop;
1166 		m->m_data = m->m_ext.ext_buf;
1167 		m->m_flags |= M_EXT;
1168 		m->m_len = m->m_ext.ext_size = iov->iov_len;
1169 		mbc->max_bytes += m->m_len;
1170 		m->m_next = 0;
1171 		*t = m;
1172 		t = &m->m_next;
1173 		iov++;
1174 	}
1175 	return (0);
1176 }
1177 
1178 static int
1179 mbc_marshal_put_mbufs(mbuf_chain_t *mbc, mbuf_t *m)
1180 {
1181 	mbuf_t	*mt;
1182 	mbuf_t	**t;
1183 	int	bytes;
1184 
1185 	if (m != NULL) {
1186 		mt = m;
1187 		bytes = mt->m_len;
1188 		while (mt->m_next != 0) {
1189 			mt = mt->m_next;
1190 			bytes += mt->m_len;
1191 		}
1192 		if (bytes != 0) {
1193 			t = &mbc->chain;
1194 			while (*t != 0) {
1195 				bytes += (*t)->m_len;
1196 				t = &(*t)->m_next;
1197 			}
1198 			*t = m;
1199 			mbc->chain_offset = bytes;
1200 		} else {
1201 			m_freem(m);
1202 		}
1203 	}
1204 	return (0);
1205 }
1206 
1207 static int
1208 mbc_marshal_put_mbuf_chain(mbuf_chain_t *mbc, mbuf_chain_t *nmbc)
1209 {
1210 	if (nmbc->chain != 0) {
1211 		if (mbc_marshal_put_mbufs(mbc, nmbc->chain))
1212 			return (DECODE_NO_MORE_DATA);
1213 		MBC_SETUP(nmbc, nmbc->max_bytes);
1214 	}
1215 	return (0);
1216 }
1217 
1218 static uint8_t
1219 mbc_marshal_fetch_byte(mbuf_chain_t *mbc)
1220 {
1221 	uint8_t	data;
1222 	mbuf_t	*m = mbc->chain;
1223 	int32_t	offset = mbc->chain_offset;
1224 
1225 	while (offset >= m->m_len) {
1226 		offset -= m->m_len;
1227 		m = m->m_next;
1228 	}
1229 	data = ((uint8_t *)m->m_data)[offset];
1230 	mbc->chain_offset++;
1231 	return (data);
1232 }
1233 
1234 static int
1235 mbc_marshal_get_char(mbuf_chain_t *mbc, uint8_t *data)
1236 {
1237 	if (MBC_ROOM_FOR(mbc, sizeof (char)) == 0) {
1238 		/* Data will never be available */
1239 		return (DECODE_NO_MORE_DATA);
1240 	}
1241 	*data = mbc_marshal_fetch_byte(mbc);
1242 	return (0);
1243 }
1244 
1245 static int
1246 mbc_marshal_get_short(mbuf_chain_t *mbc, uint16_t *data)
1247 {
1248 	uint16_t	tmp;
1249 	mbuf_t		*m = mbc->chain;
1250 	int32_t		offset = mbc->chain_offset;
1251 
1252 	if (MBC_ROOM_FOR(mbc, sizeof (short)) == 0) {
1253 		/* Data will never be available */
1254 		return (DECODE_NO_MORE_DATA);
1255 	}
1256 
1257 	while (offset >= m->m_len) {
1258 		offset -= m->m_len;
1259 		m = m->m_next;
1260 	}
1261 	if ((m->m_len - offset) >= sizeof (short)) {
1262 		*data = LE_IN16(m->m_data + offset);
1263 		mbc->chain_offset += sizeof (short);
1264 	} else {
1265 		tmp = (uint16_t)mbc_marshal_fetch_byte(mbc);
1266 		tmp |= ((uint16_t)mbc_marshal_fetch_byte(mbc)) << 8;
1267 		*data = tmp;
1268 	}
1269 	return (0);
1270 }
1271 
1272 static int
1273 mbc_marshal_get_long(mbuf_chain_t *mbc, uint32_t *data)
1274 {
1275 	uint32_t	tmp;
1276 	mbuf_t		*m = mbc->chain;
1277 	int32_t		offset = mbc->chain_offset;
1278 
1279 	if (MBC_ROOM_FOR(mbc, sizeof (int32_t)) == 0) {
1280 		/* Data will never be available */
1281 		return (DECODE_NO_MORE_DATA);
1282 	}
1283 	while (offset >= m->m_len) {
1284 		offset -= m->m_len;
1285 		m = m->m_next;
1286 	}
1287 	if ((m->m_len - offset) >= sizeof (int32_t)) {
1288 		*data = LE_IN32(m->m_data + offset);
1289 		mbc->chain_offset += sizeof (int32_t);
1290 	} else {
1291 		tmp = (uint32_t)mbc_marshal_fetch_byte(mbc);
1292 		tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 8;
1293 		tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 16;
1294 		tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 24;
1295 		*data = tmp;
1296 	}
1297 	return (0);
1298 }
1299 
1300 static uint64_t
1301 qswap(uint64_t ll)
1302 {
1303 	uint64_t v;
1304 
1305 	v = ll >> 32;
1306 	v |= ll << 32;
1307 
1308 	return (v);
1309 }
1310 
1311 static int
1312 mbc_marshal_get_odd_long_long(mbuf_chain_t *mbc, uint64_t *data)
1313 {
1314 	uint64_t	tmp;
1315 	mbuf_t		*m = mbc->chain;
1316 	int32_t		offset = mbc->chain_offset;
1317 
1318 	if (MBC_ROOM_FOR(mbc, sizeof (int64_t)) == 0) {
1319 		/* Data will never be available */
1320 		return (DECODE_NO_MORE_DATA);
1321 	}
1322 	while (offset >= m->m_len) {
1323 		offset -= m->m_len;
1324 		m = m->m_next;
1325 	}
1326 
1327 	if ((m->m_len - offset) >= sizeof (int64_t)) {
1328 		*data = qswap(LE_IN64(m->m_data + offset));
1329 		mbc->chain_offset += sizeof (int64_t);
1330 	} else {
1331 		tmp = (uint64_t)mbc_marshal_fetch_byte(mbc) << 32;
1332 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 40;
1333 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 48;
1334 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 56;
1335 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc);
1336 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 8;
1337 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 16;
1338 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 24;
1339 
1340 		*(uint64_t *)data = tmp;
1341 	}
1342 	return (0);
1343 }
1344 
1345 static int
1346 mbc_marshal_get_long_long(mbuf_chain_t *mbc, uint64_t *data)
1347 {
1348 	uint64_t	tmp;
1349 	mbuf_t		*m = mbc->chain;
1350 	int32_t		offset = mbc->chain_offset;
1351 
1352 	if (MBC_ROOM_FOR(mbc, sizeof (int64_t)) == 0) {
1353 		/* Data will never be available */
1354 		return (DECODE_NO_MORE_DATA);
1355 	}
1356 	while (offset >= m->m_len) {
1357 		offset -= m->m_len;
1358 		m = m->m_next;
1359 	}
1360 	if ((m->m_len - offset) >= sizeof (int64_t)) {
1361 		*data = LE_IN64(m->m_data + offset);
1362 		mbc->chain_offset += sizeof (int64_t);
1363 	} else {
1364 		tmp = (uint32_t)mbc_marshal_fetch_byte(mbc);
1365 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 8;
1366 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 16;
1367 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 24;
1368 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 32;
1369 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 40;
1370 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 48;
1371 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 56;
1372 		*(uint64_t *)data = tmp;
1373 	}
1374 	return (0);
1375 }
1376 
1377 /*
1378  * mbc_marshal_get_ascii_string
1379  *
1380  * The ascii string in smb includes oem chars. Since the
1381  * system needs utf8 encodes unicode char, conversion is
1382  * required to convert the oem char to unicode and then
1383  * to encode the converted wchars to utf8 format.
1384  * Therefore, the **ascii returned will be in such format
1385  * instead of the real ASCII format.
1386  */
1387 static int
1388 mbc_marshal_get_ascii_string(
1389     smb_request_t	*sr,
1390     mbuf_chain_t	*mbc,
1391     uint8_t		**ascii,
1392     int			max_ascii)
1393 {
1394 	char		*rcvbuf;
1395 	char		*ch;
1396 	int		max;
1397 	int		length = 0;
1398 
1399 	max = MALLOC_QUANTUM;
1400 	rcvbuf = smb_srm_zalloc(sr, max);
1401 
1402 	if (max_ascii == 0)
1403 		max_ascii = 0xffff;
1404 
1405 	ch = rcvbuf;
1406 	for (;;) {
1407 		while (length < max) {
1408 			if (max_ascii-- <= 0) {
1409 				*ch++ = 0;
1410 				goto multibyte_encode;
1411 			}
1412 			if (MBC_ROOM_FOR(mbc, sizeof (char)) == 0) {
1413 				/* Data will never be available */
1414 				return (DECODE_NO_MORE_DATA);
1415 			}
1416 			if ((*ch++ = mbc_marshal_fetch_byte(mbc)) == 0)
1417 				goto multibyte_encode;
1418 			length++;
1419 		}
1420 		max += MALLOC_QUANTUM;
1421 		rcvbuf = smb_srm_rezalloc(sr, rcvbuf, max);
1422 		ch = rcvbuf + length;
1423 	}
1424 
1425 multibyte_encode:
1426 	/*
1427 	 * UTF-8 encode the string for internal system use.
1428 	 */
1429 	length = strlen(rcvbuf) + 1;
1430 	*ascii = smb_srm_zalloc(sr, length * MTS_MB_CHAR_MAX);
1431 	return (mbc_marshal_cstou8("CP850", (char *)*ascii,
1432 	    (size_t)length * MTS_MB_CHAR_MAX, rcvbuf, (size_t)length));
1433 }
1434 
1435 static int
1436 mbc_marshal_get_unicode_string(smb_request_t *sr,
1437     mbuf_chain_t *mbc, uint8_t **ascii, int max_unicode)
1438 {
1439 	int		max;
1440 	uint16_t	wchar;
1441 	char		*ch;
1442 	int		emitted;
1443 	int		length = 0;
1444 
1445 	if (max_unicode == 0)
1446 		max_unicode = 0xffff;
1447 
1448 	max = MALLOC_QUANTUM;
1449 	*ascii = smb_srm_zalloc(sr, max);
1450 
1451 	ch = (char *)*ascii;
1452 	for (;;) {
1453 		while ((length + MTS_MB_CHAR_MAX) < max) {
1454 			if (max_unicode <= 0)
1455 				goto done;
1456 			max_unicode -= 2;
1457 
1458 			if (mbc_marshal_get_short(mbc, &wchar) != 0)
1459 				return (DECODE_NO_MORE_DATA);
1460 
1461 			if (wchar == 0)	goto done;
1462 
1463 			emitted = smb_wctomb(ch, wchar);
1464 			length += emitted;
1465 			ch += emitted;
1466 		}
1467 		max += MALLOC_QUANTUM;
1468 		*ascii = smb_srm_rezalloc(sr, *ascii, max);
1469 		ch = (char *)*ascii + length;
1470 	}
1471 done:	*ch = 0;
1472 	return (0);
1473 }
1474 
1475 static int /*ARGSUSED*/
1476 mbc_marshal_get_mbufs(mbuf_chain_t *mbc, int32_t bytes, mbuf_t **m)
1477 {
1478 	*m = NULL;
1479 	if (MBC_ROOM_FOR(mbc, bytes) == 0) {
1480 		/* Data will never be available */
1481 		return (DECODE_NO_MORE_DATA);
1482 	}
1483 	/* not yet implemented */
1484 	return (-1);
1485 }
1486 
1487 static int
1488 mbc_marshal_get_mbuf_chain(mbuf_chain_t *mbc, int32_t bytes, mbuf_chain_t *nmbc)
1489 {
1490 	int	rc;
1491 	mbuf_t	*m;
1492 
1493 	if (bytes == 0) {
1494 		/* Get all the rest */
1495 		bytes = mbc->max_bytes - mbc->chain_offset;
1496 	}
1497 
1498 	MBC_SETUP(nmbc, mbc->max_bytes);
1499 	if ((rc = mbc_marshal_get_mbufs(mbc, bytes, &m)) != 0) {
1500 		if (m)
1501 			m_freem(m);
1502 		return (rc);
1503 	}
1504 	nmbc->chain = m;
1505 	while (m != 0) {
1506 		bytes += m->m_len;
1507 		m = m->m_next;
1508 	}
1509 	nmbc->max_bytes = bytes;
1510 	return (0);
1511 }
1512 
1513 static int
1514 mbc_marshal_get_uio(mbuf_chain_t *mbc, struct uio *uio)
1515 {
1516 	int		i, offset;
1517 	int32_t		bytes = uio->uio_resid;
1518 	int32_t		remainder;
1519 	struct iovec	*iov;
1520 	mbuf_t		*m;
1521 
1522 	/*
1523 	 * The residual count is tested because in the case of write requests
1524 	 * with no data (smbtorture RAW-WRITE test will generate that type of
1525 	 * request) this function is called with a residual count of zero
1526 	 * bytes.
1527 	 */
1528 	if (bytes != 0) {
1529 		iov = uio->uio_iov;
1530 		uio->uio_segflg = UIO_SYSSPACE;
1531 		uio->uio_extflg = UIO_COPY_DEFAULT;
1532 
1533 		if (MBC_ROOM_FOR(mbc, bytes) == 0) {
1534 			/* Data will never be available */
1535 			return (DECODE_NO_MORE_DATA);
1536 		}
1537 
1538 		m = mbc->chain;
1539 		offset = mbc->chain_offset;
1540 		while (offset >= m->m_len) {
1541 			offset -= m->m_len;
1542 			m = m->m_next;
1543 			ASSERT((offset == 0) || (offset && m));
1544 		}
1545 
1546 		for (i = 0; (bytes > 0) && (i < uio->uio_iovcnt); i++) {
1547 			iov[i].iov_base = &m->m_data[offset];
1548 			remainder = m->m_len - offset;
1549 			if (remainder >= bytes) {
1550 				iov[i].iov_len = bytes;
1551 				mbc->chain_offset += bytes;
1552 				uio->uio_iovcnt = i + 1;
1553 				return (0);
1554 			}
1555 			iov[i].iov_len = remainder;
1556 			mbc->chain_offset += remainder;
1557 			bytes -= remainder;
1558 			m = m->m_next;
1559 			offset = 0;
1560 		}
1561 		return (DECODE_NO_MORE_DATA);
1562 	}
1563 	return (0);
1564 }
1565 
1566 static int
1567 mbc_marshal_get_skip(mbuf_chain_t *mbc, uint_t skip)
1568 {
1569 	if (MBC_ROOM_FOR(mbc, skip) == 0)
1570 		return (DECODE_NO_MORE_DATA);
1571 	mbc->chain_offset += skip;
1572 	return (0);
1573 }
1574 
1575 /*
1576  * Converts oem string to UTF-8 string with an output string of max
1577  * maxconv bytes.  The string may be truncated or not null-terminated if
1578  * there is not enough room.
1579  *
1580  * returns -1, cnt (partial conversion)  or 0 (success)
1581  */
1582 
1583 static int
1584 mbc_marshal_cstou8(char *cs, char *outbuf, size_t maxconv,
1585     char *inbuf, size_t srcbytes)
1586 {
1587 	kiconv_t	t2u;
1588 	size_t		inlen = srcbytes;
1589 	size_t		outlen = maxconv;
1590 	int		err = 0;
1591 	size_t		rc;
1592 
1593 	if ((t2u = kiconv_open("UTF-8", cs)) == (kiconv_t)-1)
1594 		return (-1);
1595 
1596 	rc = kiconv(t2u, &inbuf, &inlen, &outbuf, &outlen, &err);
1597 	(void) kiconv_close(t2u);
1598 	return ((int)rc);
1599 }
1600