xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c (revision f96bd5c800e73e351b0b6e4bd7f00b578dad29bb)
1da6c28aaSamw /*
2da6c28aaSamw  * CDDL HEADER START
3da6c28aaSamw  *
4da6c28aaSamw  * The contents of this file are subject to the terms of the
5da6c28aaSamw  * Common Development and Distribution License (the "License").
6da6c28aaSamw  * You may not use this file except in compliance with the License.
7da6c28aaSamw  *
8da6c28aaSamw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw  * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw  * See the License for the specific language governing permissions
11da6c28aaSamw  * and limitations under the License.
12da6c28aaSamw  *
13da6c28aaSamw  * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw  * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw  * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw  * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw  *
19da6c28aaSamw  * CDDL HEADER END
20da6c28aaSamw  */
21da6c28aaSamw /*
22*f96bd5c8SAlan Wright  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23da6c28aaSamw  * Use is subject to license terms.
24da6c28aaSamw  */
25da6c28aaSamw 
26da6c28aaSamw /*
27da6c28aaSamw  * SMB mbuf marshaling encode/decode.
28da6c28aaSamw  */
29da6c28aaSamw 
30bbf6f00cSJordan Brown #include <smbsrv/smb_kproto.h>
31e3f2c991SKeyur Desai 
32e3f2c991SKeyur Desai 
33da6c28aaSamw #define	MALLOC_QUANTUM	80
34da6c28aaSamw 
35da6c28aaSamw #define	DECODE_NO_ERROR		0
36da6c28aaSamw #define	DECODE_NO_MORE_DATA	1
37da6c28aaSamw #define	DECODE_ALLOCATION_ERROR	2
38da6c28aaSamw #define	DECODE_CONVERSION_ERROR	3
39da6c28aaSamw 
40e3f2c991SKeyur Desai static int mbc_marshal_cstou8(char *, char *, size_t, char *, size_t);
413db3f65cSamw static int mbc_marshal_make_room(mbuf_chain_t *, int32_t);
423db3f65cSamw static void mbc_marshal_store_byte(mbuf_chain_t *, uint8_t);
433db3f65cSamw static int mbc_marshal_put_char(mbuf_chain_t *mbc, uint8_t);
443db3f65cSamw static int mbc_marshal_put_short(mbuf_chain_t *mbc, uint16_t);
453db3f65cSamw static int mbc_marshal_put_long(mbuf_chain_t *mbc, uint32_t);
463db3f65cSamw static int mbc_marshal_put_long_long(mbuf_chain_t *mbc, uint64_t);
473db3f65cSamw static int mbc_marshal_put_ascii_string(mbuf_chain_t *, char *, int);
483db3f65cSamw static int mbc_marshal_put_unicode_string(mbuf_chain_t *, char *, int);
493db3f65cSamw static int mbc_marshal_put_uio(mbuf_chain_t *, struct uio *);
503db3f65cSamw static int mbc_marshal_put_mbufs(mbuf_chain_t *mbc, mbuf_t *m);
513db3f65cSamw static int mbc_marshal_put_mbuf_chain(mbuf_chain_t *mbc, mbuf_chain_t *nmbc);
523db3f65cSamw static uint8_t mbc_marshal_fetch_byte(mbuf_chain_t *mbc);
533db3f65cSamw static int mbc_marshal_get_char(mbuf_chain_t *mbc, uint8_t *data);
543db3f65cSamw static int mbc_marshal_get_short(mbuf_chain_t *mbc, uint16_t *data);
553db3f65cSamw static int mbc_marshal_get_long(mbuf_chain_t *mbc, uint32_t *data);
563db3f65cSamw static uint64_t qswap(uint64_t ll);
573db3f65cSamw static int mbc_marshal_get_odd_long_long(mbuf_chain_t *mbc, uint64_t *data);
583db3f65cSamw static int mbc_marshal_get_long_long(mbuf_chain_t *mbc, uint64_t *data);
59bbf6f00cSJordan Brown static int mbc_marshal_get_ascii_string(smb_request_t *, mbuf_chain_t *,
60bbf6f00cSJordan Brown     uint8_t **ascii, int);
61bbf6f00cSJordan Brown static int mbc_marshal_get_unicode_string(smb_request_t *, mbuf_chain_t *,
62bbf6f00cSJordan Brown     uint8_t **, int);
633db3f65cSamw static int mbc_marshal_get_mbufs(mbuf_chain_t *, int32_t, mbuf_t **);
643db3f65cSamw static int mbc_marshal_get_mbuf_chain(mbuf_chain_t *, int32_t, mbuf_chain_t *);
653db3f65cSamw static int mbc_marshal_get_uio(mbuf_chain_t *, struct uio *);
663db3f65cSamw static int mbc_marshal_get_skip(mbuf_chain_t *, uint_t);
67da6c28aaSamw 
68da6c28aaSamw /*
693db3f65cSamw  * smb_mbc_vdecodef
70da6c28aaSamw  *
713db3f65cSamw  * This function reads the contents of the mbc chain passed in under the list
723db3f65cSamw  * of arguments passed in.
73da6c28aaSamw  *
74da6c28aaSamw  * The format string provides a description of the parameters passed in as well
753db3f65cSamw  * as an action to be taken by smb_mbc_vdecodef().
76da6c28aaSamw  *
77da6c28aaSamw  *	%	Pointer to an SMB request structure (smb_request_t *). There
78da6c28aaSamw  *		should be only one of these in the string.
79da6c28aaSamw  *
80da6c28aaSamw  *	C	Pointer to an mbuf chain. Copy to that mbuf chain the number of
81da6c28aaSamw  *		bytes specified (number preceding C).
82da6c28aaSamw  *
83da6c28aaSamw  *	m	Pointer to an mbuf. Copy to that mbuf the number of bytes
84da6c28aaSamw  *		specified (number preceding m).
85da6c28aaSamw  *
86da6c28aaSamw  *	M	Read the 32 bit value at the current location of the mbuf chain
87da6c28aaSamw  *		and check if it matches the signature of an SMB request (SMBX).
88da6c28aaSamw  *
89da6c28aaSamw  *	b	Pointer to a buffer. Copy to that buffer the number of bytes
90da6c28aaSamw  *		specified (number preceding b).
91da6c28aaSamw  *
92da6c28aaSamw  *	c	Same as 'b'.
93da6c28aaSamw  *
94da6c28aaSamw  *	w	Pointer to a word (16bit value). Copy the next 16bit value into
95da6c28aaSamw  *		that location.
96da6c28aaSamw  *
97da6c28aaSamw  *	l	Pointer to a long (32bit value). Copy the next 32bit value into
98da6c28aaSamw  *		that location.
99da6c28aaSamw  *
100da6c28aaSamw  *	q	Pointer to a quad (64bit value). Copy the next 64bit value into
101da6c28aaSamw  *		that location.
102da6c28aaSamw  *
103da6c28aaSamw  *	Q	Same as above with a call to qswap().
104da6c28aaSamw  *
105da6c28aaSamw  *	B	Pointer to a vardata_block structure. That structure is used to
106da6c28aaSamw  *		retrieve data from the mbuf chain (an iovec type structure is
107da6c28aaSamw  *		embedded in a vardata_block).
108da6c28aaSamw  *
109da6c28aaSamw  *	D	Pointer to a vardata_block structure. That structure is used to
110da6c28aaSamw  *		retrieve data from the mbuf chain, however, two fields of the
111da6c28aaSamw  *		vardata_block structure (tag and len) are first initialized
112da6c28aaSamw  *		using the mbuf chain itself.
113da6c28aaSamw  *
114da6c28aaSamw  *	V	Same as 'D'.
115da6c28aaSamw  *
116da6c28aaSamw  *	L
117da6c28aaSamw  *
118da6c28aaSamw  *	A
119da6c28aaSamw  *
120da6c28aaSamw  *	P	Same as 'A'
121da6c28aaSamw  *
122da6c28aaSamw  *	S	Same as 'A'
123da6c28aaSamw  *
124da6c28aaSamw  *	u	Pointer to a string pointer. Allocate memory and retrieve the
125da6c28aaSamw  *		string at the current location in the mbuf chain. Store the
126da6c28aaSamw  *		address to the buffer allocated at the address specified by
127da6c28aaSamw  *		the pointer. In addition if an sr was passed and it indicates
128da6c28aaSamw  *		that the string is an unicode string, convert it.
129da6c28aaSamw  *
130da6c28aaSamw  *	s	Same as 'u' without convertion.
131da6c28aaSamw  *
132da6c28aaSamw  *	U	Same as 'u'. The string to retrieve is unicode.
133da6c28aaSamw  *
134da6c28aaSamw  *	y	Pointer to a 32bit value. Read the dos time at the current mbuf
135da6c28aaSamw  *		chain location, convert it to unix time and store it at the
136da6c28aaSamw  *		location indicated by the pointer.
137da6c28aaSamw  *
138da6c28aaSamw  *	Y	Same as 'y' bt the dos time coded in the mbuf chain is inverted.
139da6c28aaSamw  *
140da6c28aaSamw  *	.	Skip the number of bytes indicated by the number preceding '.'.
141da6c28aaSamw  *
142da6c28aaSamw  *	,	Same as '.' but take in account it is an unicode string.
143da6c28aaSamw  */
144da6c28aaSamw int
1453db3f65cSamw smb_mbc_vdecodef(mbuf_chain_t *mbc, char *fmt, va_list ap)
146da6c28aaSamw {
1473db3f65cSamw 	uint8_t		c;
1483db3f65cSamw 	uint8_t		cval;
1493db3f65cSamw 	uint8_t		*cvalp;
1503db3f65cSamw 	uint8_t		**cvalpp;
1512c2961f8Sjose borrego 	uint16_t	wval;
1523db3f65cSamw 	uint16_t	*wvalp;
153da6c28aaSamw 	uint32_t	*lvalp;
154da6c28aaSamw 	uint64_t	*llvalp;
1553db3f65cSamw 	smb_vdb_t	*vdp;
1563db3f65cSamw 	smb_request_t	*sr = NULL;
157da6c28aaSamw 	uint32_t	lval;
158da6c28aaSamw 	int		unicode = 0;
159da6c28aaSamw 	int		repc;
160da6c28aaSamw 
161da6c28aaSamw 	while ((c = *fmt++) != 0) {
162da6c28aaSamw 		repc = 1;
163da6c28aaSamw 
164da6c28aaSamw 		if ('0' <= c && c <= '9') {
165da6c28aaSamw 			repc = 0;
166da6c28aaSamw 			do {
167da6c28aaSamw 				repc = repc * 10 + c - '0';
168da6c28aaSamw 				c = *fmt++;
169da6c28aaSamw 			} while ('0' <= c && c <= '9');
170da6c28aaSamw 		} else if (c == '#') {
171da6c28aaSamw 			repc = va_arg(ap, int);
172da6c28aaSamw 			c = *fmt++;
173da6c28aaSamw 		}
174da6c28aaSamw 
175da6c28aaSamw 		switch (c) {
176da6c28aaSamw 		case '%':
177da6c28aaSamw 			sr = va_arg(ap, struct smb_request *);
178da6c28aaSamw 			unicode = sr->smb_flg2 & SMB_FLAGS2_UNICODE;
179da6c28aaSamw 			break;
180da6c28aaSamw 
181da6c28aaSamw 		case 'C':	/* Mbuf_chain */
182da6c28aaSamw 			if (mbc_marshal_get_mbuf_chain(mbc, repc,
1833db3f65cSamw 			    va_arg(ap, mbuf_chain_t *)) != 0)
1843db3f65cSamw 				return (-1);
185da6c28aaSamw 			break;
186da6c28aaSamw 
187da6c28aaSamw 		case 'm':	/* struct_mbuf */
188da6c28aaSamw 			if (mbc_marshal_get_mbufs(mbc, repc,
1893db3f65cSamw 			    va_arg(ap, mbuf_t **)) != 0)
1903db3f65cSamw 				return (-1);
191da6c28aaSamw 			break;
192da6c28aaSamw 
193da6c28aaSamw 		case 'M':
1943db3f65cSamw 			if (mbc_marshal_get_long(mbc, &lval) != 0)
195da6c28aaSamw 				/* Data will never be available */
1963db3f65cSamw 				return (-1);
1973db3f65cSamw 
198da6c28aaSamw 			if (lval != 0x424D53FF) /* 0xFF S M B */
1993db3f65cSamw 				return (-1);
200da6c28aaSamw 			break;
201da6c28aaSamw 
202da6c28aaSamw 		case 'b':
203da6c28aaSamw 		case 'c':
2043db3f65cSamw 			cvalp = va_arg(ap, uint8_t *);
2053db3f65cSamw 			if (MBC_ROOM_FOR(mbc, repc) == 0)
206da6c28aaSamw 				/* Data will never be available */
2073db3f65cSamw 				return (-1);
2083db3f65cSamw 
209da6c28aaSamw 			while (repc-- > 0)
210da6c28aaSamw 				*cvalp++ = mbc_marshal_fetch_byte(mbc);
211da6c28aaSamw 			break;
212da6c28aaSamw 
213da6c28aaSamw 		case 'w':
2143db3f65cSamw 			wvalp = va_arg(ap, uint16_t *);
215da6c28aaSamw 			while (repc-- > 0)
216da6c28aaSamw 				if (mbc_marshal_get_short(mbc, wvalp++) != 0)
2173db3f65cSamw 					return (-1);
218da6c28aaSamw 			break;
219da6c28aaSamw 
220da6c28aaSamw 		case 'l':
221da6c28aaSamw 			lvalp = va_arg(ap, uint32_t *);
222da6c28aaSamw 			while (repc-- > 0)
223da6c28aaSamw 				if (mbc_marshal_get_long(mbc, lvalp++) != 0)
2243db3f65cSamw 					return (-1);
225da6c28aaSamw 			break;
226da6c28aaSamw 
227da6c28aaSamw 		case 'q':
228da6c28aaSamw 			llvalp = va_arg(ap, uint64_t *);
229da6c28aaSamw 			while (repc-- > 0)
230da6c28aaSamw 				if (mbc_marshal_get_long_long(
231da6c28aaSamw 				    mbc, llvalp++) != 0)
2323db3f65cSamw 					return (-1);
233da6c28aaSamw 			break;
234da6c28aaSamw 
235da6c28aaSamw 		case 'Q':
236da6c28aaSamw 			llvalp = va_arg(ap, uint64_t *);
237da6c28aaSamw 			while (repc-- > 0)
238da6c28aaSamw 				if (mbc_marshal_get_odd_long_long(
239da6c28aaSamw 				    mbc, llvalp++) != 0)
2403db3f65cSamw 					return (-1);
241da6c28aaSamw 			break;
242da6c28aaSamw 
243da6c28aaSamw 		case 'B':
244da6c28aaSamw 			vdp = va_arg(ap, struct vardata_block *);
2452c2961f8Sjose borrego 			vdp->vdb_tag = 0;
2462c2961f8Sjose borrego 			vdp->vdb_len = repc;
2472c2961f8Sjose borrego 			vdp->vdb_uio.uio_iov = &vdp->vdb_iovec[0];
2482c2961f8Sjose borrego 			vdp->vdb_uio.uio_iovcnt = MAX_IOVEC;
249*f96bd5c8SAlan Wright 			vdp->vdb_uio.uio_extflg = UIO_COPY_DEFAULT;
2502c2961f8Sjose borrego 			vdp->vdb_uio.uio_resid = repc;
2512c2961f8Sjose borrego 			if (mbc_marshal_get_uio(mbc, &vdp->vdb_uio) != 0)
2523db3f65cSamw 				return (-1);
253da6c28aaSamw 			break;
254da6c28aaSamw 
2553db3f65cSamw 		case 'D':
2563db3f65cSamw 		case 'V':
257da6c28aaSamw 			vdp = va_arg(ap, struct vardata_block *);
2582c2961f8Sjose borrego 			if (mbc_marshal_get_char(mbc, &vdp->vdb_tag) != 0)
2593db3f65cSamw 				return (-1);
2602c2961f8Sjose borrego 			if (mbc_marshal_get_short(mbc, &wval) != 0)
2613db3f65cSamw 				return (-1);
2622c2961f8Sjose borrego 			vdp->vdb_len = (uint32_t)wval;
2632c2961f8Sjose borrego 			vdp->vdb_uio.uio_iov = &vdp->vdb_iovec[0];
2642c2961f8Sjose borrego 			vdp->vdb_uio.uio_iovcnt = MAX_IOVEC;
265*f96bd5c8SAlan Wright 			vdp->vdb_uio.uio_extflg = UIO_COPY_DEFAULT;
2662c2961f8Sjose borrego 			vdp->vdb_uio.uio_resid = vdp->vdb_len;
2672c2961f8Sjose borrego 			if (vdp->vdb_len != 0) {
2682c2961f8Sjose borrego 				if (mbc_marshal_get_uio(mbc,
2692c2961f8Sjose borrego 				    &vdp->vdb_uio) != 0)
2703db3f65cSamw 					return (-1);
271da6c28aaSamw 			}
272da6c28aaSamw 			break;
273da6c28aaSamw 
274da6c28aaSamw 		case 'L':
275da6c28aaSamw 			if (mbc_marshal_get_char(mbc, &cval) != 0)
2763db3f65cSamw 				return (-1);
277da6c28aaSamw 			if (cval != 2)
2783db3f65cSamw 				return (-1);
279da6c28aaSamw 			goto ascii_conversion;
280da6c28aaSamw 
2813db3f65cSamw 		case 'A':
2823db3f65cSamw 		case 'S':
283da6c28aaSamw 			if (mbc_marshal_get_char(mbc, &cval) != 0)
2843db3f65cSamw 				return (-1);
285da6c28aaSamw 			if (((c == 'A' || c == 'S') && cval != 4) ||
2863db3f65cSamw 			    (c == 'L' && cval != 2))
2873db3f65cSamw 				return (-1);
288da6c28aaSamw 			/* FALLTHROUGH */
289da6c28aaSamw 
290da6c28aaSamw 		case 'u': /* Convert from unicode if flags are set */
291da6c28aaSamw 			if (unicode)
292da6c28aaSamw 				goto unicode_translation;
293da6c28aaSamw 			/* FALLTHROUGH */
294da6c28aaSamw 
295da6c28aaSamw 		case 's':
296da6c28aaSamw ascii_conversion:
297da6c28aaSamw 			ASSERT(sr != NULL);
2983db3f65cSamw 			cvalpp = va_arg(ap, uint8_t **);
299da6c28aaSamw 			if (repc <= 1)
300da6c28aaSamw 				repc = 0;
301bbf6f00cSJordan Brown 			if (mbc_marshal_get_ascii_string(sr,
302da6c28aaSamw 			    mbc, cvalpp, repc) != 0)
3033db3f65cSamw 				return (-1);
304da6c28aaSamw 			break;
305da6c28aaSamw 
306da6c28aaSamw 		case 'U': /* Convert from unicode */
307da6c28aaSamw unicode_translation:
308da6c28aaSamw 			ASSERT(sr != 0);
3093db3f65cSamw 			cvalpp = va_arg(ap, uint8_t **);
310da6c28aaSamw 			if (repc <= 1)
311da6c28aaSamw 				repc = 0;
312da6c28aaSamw 			if (mbc->chain_offset & 1)
313da6c28aaSamw 				mbc->chain_offset++;
314bbf6f00cSJordan Brown 			if (mbc_marshal_get_unicode_string(sr,
315da6c28aaSamw 			    mbc, cvalpp, repc) != 0)
3163db3f65cSamw 				return (-1);
317da6c28aaSamw 			break;
318da6c28aaSamw 
319da6c28aaSamw 		case 'Y': /* dos time to unix time tt/dd */
320da6c28aaSamw 			lvalp = va_arg(ap, uint32_t *);
321da6c28aaSamw 			while (repc-- > 0) {
322da6c28aaSamw 				short	d, t;
323da6c28aaSamw 
324da6c28aaSamw 				if (mbc_marshal_get_short(mbc,
3253db3f65cSamw 				    (uint16_t *)&t) != 0)
3263db3f65cSamw 					return (-1);
327da6c28aaSamw 				if (mbc_marshal_get_short(mbc,
3283db3f65cSamw 				    (uint16_t *)&d) != 0)
3293db3f65cSamw 					return (-1);
330e3f2c991SKeyur Desai 				*lvalp++ = smb_time_dos_to_unix(d, t);
331da6c28aaSamw 			}
332da6c28aaSamw 			break;
333da6c28aaSamw 
334da6c28aaSamw 		case 'y': /* dos time to unix time dd/tt */
335da6c28aaSamw 			lvalp = va_arg(ap, uint32_t *);
336da6c28aaSamw 			while (repc-- > 0) {
337da6c28aaSamw 				short	d, t;
338da6c28aaSamw 
339da6c28aaSamw 				if (mbc_marshal_get_short(mbc,
3403db3f65cSamw 				    (uint16_t *)&d) != 0)
3413db3f65cSamw 					return (-1);
342da6c28aaSamw 				if (mbc_marshal_get_short(mbc,
3433db3f65cSamw 				    (uint16_t *)&t) != 0)
3443db3f65cSamw 					return (-1);
345e3f2c991SKeyur Desai 				*lvalp++ = smb_time_dos_to_unix(d, t);
346da6c28aaSamw 			}
347da6c28aaSamw 			break;
348da6c28aaSamw 
349da6c28aaSamw 		case ',':
350da6c28aaSamw 			if (unicode)
351da6c28aaSamw 				repc *= 2;
352da6c28aaSamw 			/* FALLTHROUGH */
353da6c28aaSamw 
354da6c28aaSamw 		case '.':
355da6c28aaSamw 			if (mbc_marshal_get_skip(mbc, repc) != 0)
3563db3f65cSamw 				return (-1);
357da6c28aaSamw 			break;
3583db3f65cSamw 
3593db3f65cSamw 		default:
3603db3f65cSamw 			ASSERT(0);
3613db3f65cSamw 			return (-1);
362da6c28aaSamw 		}
363da6c28aaSamw 	}
364da6c28aaSamw 	return (0);
365da6c28aaSamw }
366da6c28aaSamw 
3673db3f65cSamw /*
3683db3f65cSamw  * smb_mbc_decodef
3693db3f65cSamw  *
3703db3f65cSamw  * This function reads the contents of the mbc chain passed in under the
3713db3f65cSamw  * control of the format fmt.
3723db3f65cSamw  *
3733db3f65cSamw  * (for a description of the format string see smb_mbc_vencodef()).
3743db3f65cSamw  */
375da6c28aaSamw int
3763db3f65cSamw smb_mbc_decodef(mbuf_chain_t *mbc, char *fmt, ...)
377da6c28aaSamw {
378da6c28aaSamw 	int	xx;
379da6c28aaSamw 	va_list	ap;
380da6c28aaSamw 
381da6c28aaSamw 	va_start(ap, fmt);
3823db3f65cSamw 	xx = smb_mbc_vdecodef(mbc, fmt, ap);
383da6c28aaSamw 	va_end(ap);
384da6c28aaSamw 	return (xx);
385da6c28aaSamw }
386da6c28aaSamw 
3873db3f65cSamw /*
3883db3f65cSamw  * smb_mbc_peek
3893db3f65cSamw  *
3903db3f65cSamw  * This function reads the contents of the mbc passed in at the specified offset
3913db3f65cSamw  * under the control of the format fmt. The offset of the chain passed in is not
3923db3f65cSamw  * modified.
3933db3f65cSamw  *
3943db3f65cSamw  * (for a description of the format string see smb_mbc_vdecodef()).
3953db3f65cSamw  */
396da6c28aaSamw int
3973db3f65cSamw smb_mbc_peek(mbuf_chain_t *mbc, int offset, char *fmt, ...)
398da6c28aaSamw {
3993db3f65cSamw 	mbuf_chain_t	tmp;
400da6c28aaSamw 	va_list		ap;
4013db3f65cSamw 	int		xx;
402da6c28aaSamw 
403da6c28aaSamw 	va_start(ap, fmt);
404da6c28aaSamw 
4053db3f65cSamw 	(void) MBC_SHADOW_CHAIN(&tmp, mbc, offset, mbc->max_bytes - offset);
4063db3f65cSamw 	xx = smb_mbc_vdecodef(&tmp, fmt, ap);
407da6c28aaSamw 	va_end(ap);
4083db3f65cSamw 	return (xx);
409da6c28aaSamw }
410da6c28aaSamw 
411da6c28aaSamw /*
4123db3f65cSamw  * smb_mbc_vencodef
4133db3f65cSamw  *
4143db3f65cSamw  * This function builds a stream of bytes in the mbc chain passed in under the
4153db3f65cSamw  * control of the list of arguments passed in.
416da6c28aaSamw  *
417da6c28aaSamw  * The format string provides a description of the parameters passed in as well
4183db3f65cSamw  * as an action to be taken by smb_mbc_vencodef().
419da6c28aaSamw  *
420da6c28aaSamw  *	\b	Restore the mbuf chain offset to its initial value.
421da6c28aaSamw  *
422da6c28aaSamw  *	%	Pointer to an SMB request structure (smb_request_t *). There
423da6c28aaSamw  *		should be only one of these in the string. If an sr in present
424da6c28aaSamw  *		it will be used to determine if unicode conversion should be
425da6c28aaSamw  *		applied to the strings.
426da6c28aaSamw  *
427da6c28aaSamw  *	C	Pointer to an mbuf chain. Copy that mbuf chain into the
428da6c28aaSamw  *		destination mbuf chain.
429da6c28aaSamw  *
430da6c28aaSamw  *	D	Pointer to a vardata_block structure. Copy the data described
431da6c28aaSamw  *		by that structure into the mbuf chain. The tag field is hard
432da6c28aaSamw  *		coded to '1'.
433da6c28aaSamw  *
434da6c28aaSamw  *	M	Write the SMB request signature ('SMBX') into the mbuf chain.
435da6c28aaSamw  *
436da6c28aaSamw  *	T	Pointer to a timestruc_t. Convert the content of the structure
437da6c28aaSamw  *		into NT time and store the result of the conversion in the
438da6c28aaSamw  *		mbuf chain.
439da6c28aaSamw  *
440da6c28aaSamw  *	V	Same as 'D' but the tag field is hard coded to '5'.
441da6c28aaSamw  *
442da6c28aaSamw  *	b	Byte. Store the byte or the nymber of bytes specified into the
443da6c28aaSamw  *		the mbuf chain. A format string like this "2b" would require 2
444da6c28aaSamw  *		bytes to be passed in.
445da6c28aaSamw  *
446da6c28aaSamw  *	m	Pointer to an mbuf. Copy the contents of the mbuf into the mbuf
447da6c28aaSamw  *		chain.
448da6c28aaSamw  *
449da6c28aaSamw  *	c	Pointer to a buffer. Copy the buffer into the mbuf chain. The
450da6c28aaSamw  *		size of the buffer is indicated by the number preceding 'c'.
451da6c28aaSamw  *
452da6c28aaSamw  *	w	Word (16bit value). Store the word or the number of words
453da6c28aaSamw  *              specified into the the mbuf chain. A format string like this
454da6c28aaSamw  *		"2w" would require 2 words to be passed in.
455da6c28aaSamw  *
456da6c28aaSamw  *	l	Long (32bit value). Store the long or the number of longs
457da6c28aaSamw  *		specified into the the mbuf chain. A format string like this
458da6c28aaSamw  *		"2l" would require 2 longs to be passed in.
459da6c28aaSamw  *
460da6c28aaSamw  *	q	Quad (64bit value). Store the quad or the number of quads
461da6c28aaSamw  *		specified into the the mbuf chain. A format string like this
462da6c28aaSamw  *		"2q" would require 2 quads to be passed in.
463da6c28aaSamw  *
464da6c28aaSamw  *	L	Pointer to a string. Store the string passed in into the mbuf
465da6c28aaSamw  *		chain preceded with a tag value of '2'.
466da6c28aaSamw  *
467da6c28aaSamw  *	S	Pointer to a string. Store the string passed in into the mbuf
468da6c28aaSamw  *		chain preceded with a tag value of '4'. Applied a unicode
469da6c28aaSamw  *		conversion is appropriate.
470da6c28aaSamw  *
471da6c28aaSamw  *	A	Same as 'S'
472da6c28aaSamw  *
473da6c28aaSamw  *	P	Pointer to a string. Store the string passed in into the mbuf
474da6c28aaSamw  *		chain preceded with a tag value of '5'. Applied a unicode
475da6c28aaSamw  *		conversion is appropriate.
476da6c28aaSamw  *
477da6c28aaSamw  *	u	Pointer to a string. Store the string passed in into the mbuf
478da6c28aaSamw  *		chain. Applied a unicode conversion is appropriate.
479da6c28aaSamw  *
480da6c28aaSamw  *	s	Pointer to a string. Store the string passed in into the mbuf
481da6c28aaSamw  *		chain.
482da6c28aaSamw  *
483da6c28aaSamw  *	Y	Date/Time.  Store the Date/Time or the number of Date/Time(s)
484da6c28aaSamw  *		specified into the the mbuf chain. A format string like this
485da6c28aaSamw  *		"2Y" would require 2 Date/Time values. The Date/Time is
486da6c28aaSamw  *		converted to DOS before storing.
487da6c28aaSamw  *
488da6c28aaSamw  *	y	Same as 'Y'. The order of Date and Time is reversed.
489da6c28aaSamw  *
490da6c28aaSamw  *	,	Character. Store the character or number of character specified
491da6c28aaSamw  *		into the mbuf chain.  A format string like this "2c" would
492da6c28aaSamw  *		require 2 characters to be passed in. A unicode conversion is
493da6c28aaSamw  *		applied if appropriate.
494da6c28aaSamw  *
495da6c28aaSamw  *	.	Same as '`' without unicode conversion.
496da6c28aaSamw  *
497da6c28aaSamw  *	U	Align the offset of the mbuf chain on a 16bit boundary.
498da6c28aaSamw  */
499da6c28aaSamw int
5003db3f65cSamw smb_mbc_vencodef(mbuf_chain_t *mbc, char *fmt, va_list ap)
501da6c28aaSamw {
5023db3f65cSamw 	uint8_t		*cvalp;
503da6c28aaSamw 	timestruc_t	*tvp;
5043db3f65cSamw 	smb_vdb_t	*vdp;
5053db3f65cSamw 	smb_request_t	*sr = NULL;
5063db3f65cSamw 	uint64_t	llval;
507da6c28aaSamw 	int64_t		nt_time;
5083db3f65cSamw 	uint32_t	lval;
5093db3f65cSamw 	uint_t		tag;
510da6c28aaSamw 	int		unicode = 0;
511da6c28aaSamw 	int		repc = 1;
5123db3f65cSamw 	uint16_t	wval;
5133db3f65cSamw 	uint8_t		cval;
5143db3f65cSamw 	uint8_t		c;
515da6c28aaSamw 
516da6c28aaSamw 	while ((c = *fmt++) != 0) {
517da6c28aaSamw 		repc = 1;
518da6c28aaSamw 
519da6c28aaSamw 		if ('0' <= c && c <= '9') {
520da6c28aaSamw 			repc = 0;
521da6c28aaSamw 			do {
522da6c28aaSamw 				repc = repc * 10 + c - '0';
523da6c28aaSamw 				c = *fmt++;
524da6c28aaSamw 			} while ('0' <= c && c <= '9');
525da6c28aaSamw 		} else if (c == '#') {
526da6c28aaSamw 			repc = va_arg(ap, int);
527da6c28aaSamw 			c = *fmt++;
528da6c28aaSamw 		}
529da6c28aaSamw 
530da6c28aaSamw 		switch (c) {
531da6c28aaSamw 		case '%':
532da6c28aaSamw 			sr = va_arg(ap, struct smb_request *);
533da6c28aaSamw 			unicode = sr->smb_flg2 & SMB_FLAGS2_UNICODE;
534da6c28aaSamw 			break;
535da6c28aaSamw 
536da6c28aaSamw 		case 'C':	/* Mbuf_chain */
537da6c28aaSamw 			if (mbc_marshal_put_mbuf_chain(mbc,
5383db3f65cSamw 			    va_arg(ap, mbuf_chain_t *)) != 0)
539da6c28aaSamw 				return (DECODE_NO_MORE_DATA);
540da6c28aaSamw 			break;
541da6c28aaSamw 
542da6c28aaSamw 		case 'D':
543da6c28aaSamw 			vdp = va_arg(ap, struct vardata_block *);
544da6c28aaSamw 
545da6c28aaSamw 			if (mbc_marshal_put_char(mbc, 1) != 0)
546da6c28aaSamw 				return (DECODE_NO_MORE_DATA);
5472c2961f8Sjose borrego 			if (mbc_marshal_put_short(mbc, vdp->vdb_len) != 0)
548da6c28aaSamw 				return (DECODE_NO_MORE_DATA);
5492c2961f8Sjose borrego 			if (mbc_marshal_put_uio(mbc, &vdp->vdb_uio) != 0)
550da6c28aaSamw 				return (DECODE_NO_MORE_DATA);
551da6c28aaSamw 			break;
552da6c28aaSamw 
553da6c28aaSamw 		case 'M':
554da6c28aaSamw 			/* 0xFF S M B */
555da6c28aaSamw 			if (mbc_marshal_put_long(mbc, 0x424D53FF))
556da6c28aaSamw 				return (DECODE_NO_MORE_DATA);
557da6c28aaSamw 			break;
558da6c28aaSamw 
559da6c28aaSamw 		case 'T':
560da6c28aaSamw 			tvp = va_arg(ap, timestruc_t *);
561e3f2c991SKeyur Desai 			nt_time = smb_time_unix_to_nt(tvp);
562da6c28aaSamw 			if (mbc_marshal_put_long_long(mbc, nt_time) != 0)
563da6c28aaSamw 				return (DECODE_NO_MORE_DATA);
564da6c28aaSamw 			break;
565da6c28aaSamw 
566da6c28aaSamw 		case 'V':
567da6c28aaSamw 			vdp = va_arg(ap, struct vardata_block *);
568da6c28aaSamw 
569da6c28aaSamw 			if (mbc_marshal_put_char(mbc, 5) != 0)
570da6c28aaSamw 				return (DECODE_NO_MORE_DATA);
5712c2961f8Sjose borrego 			if (mbc_marshal_put_short(mbc, vdp->vdb_len) != 0)
572da6c28aaSamw 				return (DECODE_NO_MORE_DATA);
5732c2961f8Sjose borrego 			if (mbc_marshal_put_uio(mbc, &vdp->vdb_uio) != 0)
574da6c28aaSamw 				return (DECODE_NO_MORE_DATA);
575da6c28aaSamw 			break;
576da6c28aaSamw 
577da6c28aaSamw 		case 'b':
578da6c28aaSamw 			while (repc-- > 0) {
579da6c28aaSamw 				cval = va_arg(ap, int);
580da6c28aaSamw 				if (mbc_marshal_put_char(mbc, cval) != 0)
581da6c28aaSamw 					return (DECODE_NO_MORE_DATA);
582da6c28aaSamw 			}
583da6c28aaSamw 			break;
584da6c28aaSamw 
585da6c28aaSamw 		case 'm':	/* struct_mbuf */
586da6c28aaSamw 			if (mbc_marshal_put_mbufs(mbc,
5873db3f65cSamw 			    va_arg(ap, mbuf_t *)) != 0)
588da6c28aaSamw 				return (DECODE_NO_MORE_DATA);
589da6c28aaSamw 			break;
590da6c28aaSamw 
591da6c28aaSamw 		case 'c':
5923db3f65cSamw 			cvalp = va_arg(ap, uint8_t *);
593da6c28aaSamw 			while (repc-- > 0) {
594da6c28aaSamw 				if (mbc_marshal_put_char(mbc,
595da6c28aaSamw 				    *cvalp++) != 0)
596da6c28aaSamw 					return (DECODE_NO_MORE_DATA);
597da6c28aaSamw 			}
598da6c28aaSamw 			break;
599da6c28aaSamw 
600da6c28aaSamw 		case 'w':
601da6c28aaSamw 			while (repc-- > 0) {
602da6c28aaSamw 				wval = va_arg(ap, int);
603da6c28aaSamw 				if (mbc_marshal_put_short(mbc, wval) != 0)
604da6c28aaSamw 					return (DECODE_NO_MORE_DATA);
605da6c28aaSamw 			}
606da6c28aaSamw 			break;
607da6c28aaSamw 
608da6c28aaSamw 		case 'l':
609da6c28aaSamw 			while (repc-- > 0) {
610da6c28aaSamw 				lval = va_arg(ap, uint32_t);
611da6c28aaSamw 				if (mbc_marshal_put_long(mbc, lval) != 0)
612da6c28aaSamw 					return (DECODE_NO_MORE_DATA);
613da6c28aaSamw 			}
614da6c28aaSamw 			break;
615da6c28aaSamw 
616da6c28aaSamw 		case 'q':
617da6c28aaSamw 			while (repc-- > 0) {
618da6c28aaSamw 				llval = va_arg(ap, uint64_t);
619da6c28aaSamw 				if (mbc_marshal_put_long_long(mbc, llval) != 0)
620da6c28aaSamw 					return (DECODE_NO_MORE_DATA);
621da6c28aaSamw 			}
622da6c28aaSamw 			break;
623da6c28aaSamw 
624da6c28aaSamw 
625da6c28aaSamw 		case 'L':
626da6c28aaSamw 			tag = 2;
627da6c28aaSamw 			goto ascii_conversion;
628da6c28aaSamw 
629da6c28aaSamw 		case 'S':
6303db3f65cSamw 		case 'A':
6313db3f65cSamw 			tag = 4;
6323db3f65cSamw 			goto tagged_str;
6333db3f65cSamw 
6343db3f65cSamw 		case 'P':
6353db3f65cSamw 			tag = 3;
6363db3f65cSamw 			goto tagged_str;
6373db3f65cSamw 
638da6c28aaSamw 		tagged_str:
639da6c28aaSamw 			if (mbc_marshal_put_char(mbc, tag) != 0)
640da6c28aaSamw 				return (DECODE_NO_MORE_DATA);
641da6c28aaSamw 			/* FALLTHROUGH */
642da6c28aaSamw 
643da6c28aaSamw 		case 'u':	/* Convert from unicode if flags are set */
644da6c28aaSamw 			if (unicode)
645da6c28aaSamw 				goto unicode_translation;
646da6c28aaSamw 			/* FALLTHROUGH */
647da6c28aaSamw 
648da6c28aaSamw 		case 's':	/* ASCII/multibyte string */
6493db3f65cSamw ascii_conversion:	cvalp = va_arg(ap, uint8_t *);
650da6c28aaSamw 			if (mbc_marshal_put_ascii_string(mbc,
651da6c28aaSamw 			    (char *)cvalp, repc) != 0)
652da6c28aaSamw 				return (DECODE_NO_MORE_DATA);
653da6c28aaSamw 			break;
654da6c28aaSamw 
655da6c28aaSamw 		case 'Y':		/* int32_t, encode dos date/time */
656da6c28aaSamw 			while (repc-- > 0) {
6573db3f65cSamw 				uint16_t	d, t;
658da6c28aaSamw 
659da6c28aaSamw 				lval = va_arg(ap, uint32_t);
660e3f2c991SKeyur Desai 				smb_time_unix_to_dos(lval,
661da6c28aaSamw 				    (short *)&d, (short *)&t);
662da6c28aaSamw 				if (mbc_marshal_put_short(mbc, t) != 0)
663da6c28aaSamw 					return (DECODE_NO_MORE_DATA);
664da6c28aaSamw 				if (mbc_marshal_put_short(mbc, d) != 0)
665da6c28aaSamw 					return (DECODE_NO_MORE_DATA);
666da6c28aaSamw 			}
667da6c28aaSamw 			break;
668da6c28aaSamw 
669da6c28aaSamw 		case 'y':		/* int32_t, encode dos date/time */
670da6c28aaSamw 			while (repc-- > 0) {
6713db3f65cSamw 				uint16_t	d, t;
672da6c28aaSamw 
673da6c28aaSamw 				lval = va_arg(ap, uint32_t);
674e3f2c991SKeyur Desai 				smb_time_unix_to_dos(lval,
675da6c28aaSamw 				    (short *)&d, (short *)&t);
676da6c28aaSamw 				if (mbc_marshal_put_short(mbc, d) != 0)
677da6c28aaSamw 					return (DECODE_NO_MORE_DATA);
678da6c28aaSamw 				if (mbc_marshal_put_short(mbc, t) != 0)
679da6c28aaSamw 					return (DECODE_NO_MORE_DATA);
680da6c28aaSamw 			}
681da6c28aaSamw 			break;
682da6c28aaSamw 
683da6c28aaSamw 		case ',':
684da6c28aaSamw 			if (unicode)
685da6c28aaSamw 				repc *= 2;
686da6c28aaSamw 			/* FALLTHROUGH */
687da6c28aaSamw 
688da6c28aaSamw 		case '.':
689da6c28aaSamw 			while (repc-- > 0)
690da6c28aaSamw 				if (mbc_marshal_put_char(mbc, 0) != 0)
691da6c28aaSamw 					return (DECODE_NO_MORE_DATA);
692da6c28aaSamw 			break;
693da6c28aaSamw 
694da6c28aaSamw 		case 'U': /* Convert to unicode, align to word boundary */
695da6c28aaSamw unicode_translation:
696da6c28aaSamw 			if (mbc->chain_offset & 1)
697da6c28aaSamw 				mbc->chain_offset++;
6983db3f65cSamw 			cvalp = va_arg(ap, uint8_t *);
699da6c28aaSamw 			if (mbc_marshal_put_unicode_string(mbc,
700da6c28aaSamw 			    (char *)cvalp, repc) != 0)
701da6c28aaSamw 				return (DECODE_NO_MORE_DATA);
702da6c28aaSamw 			break;
7033db3f65cSamw 
7043db3f65cSamw 		default:
7053db3f65cSamw 			ASSERT(0);
7063db3f65cSamw 			return (-1);
707da6c28aaSamw 		}
708da6c28aaSamw 	}
709da6c28aaSamw 	return (0);
710da6c28aaSamw }
711da6c28aaSamw 
7123db3f65cSamw /*
7133db3f65cSamw  * smb_mbc_encodef
7143db3f65cSamw  *
7153db3f65cSamw  * This function builds a stream of bytes in the mbc chain passed in under the
7163db3f65cSamw  * control of the format fmt.
7173db3f65cSamw  *
7183db3f65cSamw  * (for a description of the format string see smb_mbc_vencodef()).
7193db3f65cSamw  */
720da6c28aaSamw int
7213db3f65cSamw smb_mbc_encodef(mbuf_chain_t *mbc, char *fmt, ...)
722da6c28aaSamw {
723da6c28aaSamw 	int	rc;
724da6c28aaSamw 	va_list	ap;
725da6c28aaSamw 
726da6c28aaSamw 	va_start(ap, fmt);
7273db3f65cSamw 	rc = smb_mbc_vencodef(mbc, fmt, ap);
728da6c28aaSamw 	va_end(ap);
729da6c28aaSamw 	return (rc);
730da6c28aaSamw }
731da6c28aaSamw 
7323db3f65cSamw /*
7333db3f65cSamw  * smb_mbc_poke
7343db3f65cSamw  *
7353db3f65cSamw  * This function writes a stream of bytes in the mbc passed in at the specified
7363db3f65cSamw  * offset under the control of the format fmt. The offset of the chain passed in
7373db3f65cSamw  * is not modified.
7383db3f65cSamw  *
7393db3f65cSamw  * (for a description of the format string see smb_mbc_vencodef()).
7403db3f65cSamw  */
741da6c28aaSamw int
7423db3f65cSamw smb_mbc_poke(mbuf_chain_t *mbc, int offset, char *fmt, ...)
743da6c28aaSamw {
744da6c28aaSamw 	int		xx;
7453db3f65cSamw 	mbuf_chain_t	tmp;
746da6c28aaSamw 	va_list		ap;
747da6c28aaSamw 
748da6c28aaSamw 	(void) MBC_SHADOW_CHAIN(&tmp, mbc, offset, mbc->max_bytes - offset);
749da6c28aaSamw 	va_start(ap, fmt);
7503db3f65cSamw 	xx = smb_mbc_vencodef(&tmp, fmt, ap);
751da6c28aaSamw 	va_end(ap);
752da6c28aaSamw 	return (xx);
753da6c28aaSamw }
7543db3f65cSamw 
7553db3f65cSamw /*
7563db3f65cSamw  * Put data into mbuf chain allocating as needed.
7573db3f65cSamw  * Adds room to end of mbuf chain if needed.
7583db3f65cSamw  */
7593db3f65cSamw static int
7603db3f65cSamw mbc_marshal_make_room(mbuf_chain_t *mbc, int32_t bytes_needed)
7613db3f65cSamw {
7623db3f65cSamw 	mbuf_t	*m;
7633db3f65cSamw 	mbuf_t	*l;
7643db3f65cSamw 	int32_t	bytes_available;
7653db3f65cSamw 
7663db3f65cSamw 	bytes_needed += mbc->chain_offset;
7673db3f65cSamw 	if (bytes_needed > mbc->max_bytes)
7683db3f65cSamw 		return (EMSGSIZE);
7693db3f65cSamw 
7703db3f65cSamw 	if ((m = mbc->chain) == 0) {
7713db3f65cSamw 		MGET(m, M_WAIT, MT_DATA);
7723db3f65cSamw 		m->m_len = 0;
7733db3f65cSamw 		if (mbc->max_bytes > MLEN)
7743db3f65cSamw 			MCLGET(m, M_WAIT);
7753db3f65cSamw 		mbc->chain = m;
7763db3f65cSamw 		/* xxxx */
7773db3f65cSamw 		/* ^    */
7783db3f65cSamw 	}
7793db3f65cSamw 
7803db3f65cSamw 	/* ---- ----- --xx ---xxx */
7813db3f65cSamw 	/* ^			  */
7823db3f65cSamw 
7833db3f65cSamw 	l = 0;
7843db3f65cSamw 	while ((m != 0) && (bytes_needed >= m->m_len)) {
7853db3f65cSamw 		l = m;
7863db3f65cSamw 		bytes_needed -= m->m_len;
7873db3f65cSamw 		m = m->m_next;
7883db3f65cSamw 	}
7893db3f65cSamw 
7903db3f65cSamw 	if ((bytes_needed == 0) || (m != 0)) {
7913db3f65cSamw 		/* We have enough room already */
7923db3f65cSamw 		return (0);
7933db3f65cSamw 	}
7943db3f65cSamw 
7953db3f65cSamw 	/* ---- ----- --xx ---xxx */
7963db3f65cSamw 	/*			 ^ */
7973db3f65cSamw 	/* Back up to start of last mbuf */
7983db3f65cSamw 	m = l;
7993db3f65cSamw 	bytes_needed += m->m_len;
8003db3f65cSamw 
8013db3f65cSamw 	/* ---- ----- --xx ---xxx */
8023db3f65cSamw 	/*		   ^	  */
8033db3f65cSamw 
8043db3f65cSamw 	bytes_available = (m->m_flags & M_EXT) ?
8053db3f65cSamw 	    m->m_ext.ext_size : MLEN;
8063db3f65cSamw 
8073db3f65cSamw 	/* ---- ----- --xx ---xxx */
8083db3f65cSamw 	/*		   ^	  */
8093db3f65cSamw 	while ((bytes_needed != 0) && (bytes_needed > bytes_available)) {
8103db3f65cSamw 		m->m_len = bytes_available;
8113db3f65cSamw 		bytes_needed -= m->m_len;
8123db3f65cSamw 		/* ---- ----- --xx ------ */
8133db3f65cSamw 		/*		   ^	  */
8143db3f65cSamw 
8153db3f65cSamw 		MGET(m->m_next, M_WAIT, MT_DATA);
8163db3f65cSamw 		m = m->m_next;
8173db3f65cSamw 		m->m_len = 0;
8183db3f65cSamw 		if (bytes_needed > MLEN)
8193db3f65cSamw 			MCLGET(m, M_WAIT);
8203db3f65cSamw 
8213db3f65cSamw 		bytes_available = (m->m_flags & M_EXT) ?
8223db3f65cSamw 		    m->m_ext.ext_size : MLEN;
8233db3f65cSamw 
8243db3f65cSamw 		/* ---- ----- --xx ------ xxxx */
8253db3f65cSamw 		/*			  ^    */
8263db3f65cSamw 	}
8273db3f65cSamw 
8283db3f65cSamw 	/* ---- ----- --xx ------ xxxx */
8293db3f65cSamw 	/*			  ^    */
8303db3f65cSamw 	/* Expand last tail as needed */
8313db3f65cSamw 	if (m->m_len <= bytes_needed) {
8323db3f65cSamw 		m->m_len = bytes_needed;
8333db3f65cSamw 		/* ---- ----- --xx ------ --xx */
8343db3f65cSamw 		/*			   ^   */
8353db3f65cSamw 	}
8363db3f65cSamw 
8373db3f65cSamw 	return (0);
8383db3f65cSamw }
8393db3f65cSamw 
8403db3f65cSamw static void
8413db3f65cSamw mbc_marshal_store_byte(mbuf_chain_t *mbc, uint8_t data)
8423db3f65cSamw {
8433db3f65cSamw 	mbuf_t	*m = mbc->chain;
8443db3f65cSamw 	int32_t	cur_offset = mbc->chain_offset;
8453db3f65cSamw 
8463db3f65cSamw 	/*
8473db3f65cSamw 	 * Scan forward looking for the last data currently in chain.
8483db3f65cSamw 	 */
8493db3f65cSamw 	while (cur_offset >= m->m_len) {
8503db3f65cSamw 		cur_offset -= m->m_len;
8513db3f65cSamw 		m = m->m_next;
8523db3f65cSamw 	}
8533db3f65cSamw 	((char *)m->m_data)[cur_offset] = data;
8543db3f65cSamw 	mbc->chain_offset++;
8553db3f65cSamw }
8563db3f65cSamw 
8573db3f65cSamw static int
8583db3f65cSamw mbc_marshal_put_char(mbuf_chain_t *mbc, uint8_t data)
8593db3f65cSamw {
8603db3f65cSamw 	if (mbc_marshal_make_room(mbc, sizeof (char)) != 0)
8613db3f65cSamw 		return (DECODE_NO_MORE_DATA);
8623db3f65cSamw 	mbc_marshal_store_byte(mbc, data);
8633db3f65cSamw 	return (0);
8643db3f65cSamw }
8653db3f65cSamw 
8663db3f65cSamw static int
8673db3f65cSamw mbc_marshal_put_short(mbuf_chain_t *mbc, uint16_t data)
8683db3f65cSamw {
8693db3f65cSamw 	if (mbc_marshal_make_room(mbc, sizeof (short)))
8703db3f65cSamw 		return (DECODE_NO_MORE_DATA);
8713db3f65cSamw 	mbc_marshal_store_byte(mbc, data);
8723db3f65cSamw 	mbc_marshal_store_byte(mbc, data >> 8);
8733db3f65cSamw 	return (0);
8743db3f65cSamw }
8753db3f65cSamw 
8763db3f65cSamw static int
8773db3f65cSamw mbc_marshal_put_long(mbuf_chain_t *mbc, uint32_t data)
8783db3f65cSamw {
8793db3f65cSamw 	if (mbc_marshal_make_room(mbc, sizeof (int32_t)))
8803db3f65cSamw 		return (DECODE_NO_MORE_DATA);
8813db3f65cSamw 	mbc_marshal_store_byte(mbc, data);
8823db3f65cSamw 	mbc_marshal_store_byte(mbc, data >> 8);
8833db3f65cSamw 	mbc_marshal_store_byte(mbc, data >> 16);
8843db3f65cSamw 	mbc_marshal_store_byte(mbc, data >> 24);
8853db3f65cSamw 	return (0);
8863db3f65cSamw }
8873db3f65cSamw 
8883db3f65cSamw static int
8893db3f65cSamw mbc_marshal_put_long_long(mbuf_chain_t *mbc, uint64_t data)
8903db3f65cSamw {
8913db3f65cSamw 	if (mbc_marshal_make_room(mbc, sizeof (int64_t)))
8923db3f65cSamw 		return (DECODE_NO_MORE_DATA);
8933db3f65cSamw 
8943db3f65cSamw 	mbc_marshal_store_byte(mbc, data);
8953db3f65cSamw 	mbc_marshal_store_byte(mbc, data >> 8);
8963db3f65cSamw 	mbc_marshal_store_byte(mbc, data >> 16);
8973db3f65cSamw 	mbc_marshal_store_byte(mbc, data >> 24);
8983db3f65cSamw 	mbc_marshal_store_byte(mbc, data >> 32);
8993db3f65cSamw 	mbc_marshal_store_byte(mbc, data >> 40);
9003db3f65cSamw 	mbc_marshal_store_byte(mbc, data >> 48);
9013db3f65cSamw 	mbc_marshal_store_byte(mbc, data >> 56);
9023db3f65cSamw 	return (0);
9033db3f65cSamw }
9043db3f65cSamw 
9053db3f65cSamw /*
9063db3f65cSamw  * When need to convert from UTF-8 (internal format) to a single
9073db3f65cSamw  * byte string (external format ) when marshalling a string.
9083db3f65cSamw  */
9093db3f65cSamw static int
9103db3f65cSamw mbc_marshal_put_ascii_string(mbuf_chain_t *mbc, char *mbs, int repc)
9113db3f65cSamw {
912bbf6f00cSJordan Brown 	smb_wchar_t	wide_char;
9133db3f65cSamw 	int		nbytes;
9143db3f65cSamw 	int		length;
9153db3f65cSamw 
916bbf6f00cSJordan Brown 	if ((length = smb_sbequiv_strlen(mbs)) == -1)
9173db3f65cSamw 		return (DECODE_NO_MORE_DATA);
9183db3f65cSamw 
9193db3f65cSamw 	length += sizeof (char);
9203db3f65cSamw 
9213db3f65cSamw 	if ((repc > 1) && (repc < length))
9223db3f65cSamw 		length = repc;
9233db3f65cSamw 	if (mbc_marshal_make_room(mbc, length))
9243db3f65cSamw 		return (DECODE_NO_MORE_DATA);
9253db3f65cSamw 
9263db3f65cSamw 	while (*mbs) {
9273db3f65cSamw 		/*
9283db3f65cSamw 		 * We should restore oem chars here.
9293db3f65cSamw 		 */
930bbf6f00cSJordan Brown 		nbytes = smb_mbtowc(&wide_char, mbs, MTS_MB_CHAR_MAX);
9313db3f65cSamw 		if (nbytes == -1)
9323db3f65cSamw 			return (DECODE_NO_MORE_DATA);
9333db3f65cSamw 
9343db3f65cSamw 		mbc_marshal_store_byte(mbc, (uint8_t)wide_char);
9353db3f65cSamw 
9363db3f65cSamw 		if (wide_char & 0xFF00)
9373db3f65cSamw 			mbc_marshal_store_byte(mbc, wide_char >> 8);
9383db3f65cSamw 
9393db3f65cSamw 		mbs += nbytes;
9403db3f65cSamw 	}
9413db3f65cSamw 
9423db3f65cSamw 	mbc_marshal_store_byte(mbc, 0);
9433db3f65cSamw 	return (0);
9443db3f65cSamw }
9453db3f65cSamw 
9463db3f65cSamw static int
9473db3f65cSamw mbc_marshal_put_unicode_string(mbuf_chain_t *mbc, char *ascii, int repc)
9483db3f65cSamw {
949bbf6f00cSJordan Brown 	smb_wchar_t	wchar;
9503db3f65cSamw 	int		consumed;
9513db3f65cSamw 	int		length;
9523db3f65cSamw 
953bbf6f00cSJordan Brown 	if ((length = smb_wcequiv_strlen(ascii)) == -1)
9543db3f65cSamw 		return (DECODE_NO_MORE_DATA);
9553db3f65cSamw 
956bbf6f00cSJordan Brown 	length += sizeof (smb_wchar_t);
9573db3f65cSamw 
9583db3f65cSamw 	if ((repc > 1) && (repc < length))
9593db3f65cSamw 		length = repc;
9603db3f65cSamw 
9613db3f65cSamw 	if (mbc_marshal_make_room(mbc, length))
9623db3f65cSamw 		return (DECODE_NO_MORE_DATA);
9633db3f65cSamw 	while (length > 0) {
964bbf6f00cSJordan Brown 		consumed = smb_mbtowc(&wchar, ascii, MTS_MB_CHAR_MAX);
9653db3f65cSamw 		if (consumed == -1)
9663db3f65cSamw 			break;	/* Invalid sequence */
9673db3f65cSamw 		/*
9683db3f65cSamw 		 * Note that consumed will be 0 when the null terminator
9693db3f65cSamw 		 * is encountered and ascii will not be advanced beyond
9703db3f65cSamw 		 * that point. Length will continue to be decremented so
9713db3f65cSamw 		 * we won't get stuck here.
9723db3f65cSamw 		 */
9733db3f65cSamw 		ascii += consumed;
9743db3f65cSamw 		mbc_marshal_store_byte(mbc, wchar);
9753db3f65cSamw 		mbc_marshal_store_byte(mbc, wchar >> 8);
976bbf6f00cSJordan Brown 		length -= sizeof (smb_wchar_t);
9773db3f65cSamw 	}
9783db3f65cSamw 	return (0);
9793db3f65cSamw }
9803db3f65cSamw 
9813db3f65cSamw static int
9823db3f65cSamw mbc_marshal_put_uio(mbuf_chain_t *mbc, struct uio *uio)
9833db3f65cSamw {
9843db3f65cSamw 	mbuf_t		**t;
9853db3f65cSamw 	mbuf_t		*m = NULL;
9863db3f65cSamw 	struct iovec	*iov = uio->uio_iov;
9873db3f65cSamw 	int32_t		i, iov_cnt = uio->uio_iovcnt;
9883db3f65cSamw 
9893db3f65cSamw 	iov = uio->uio_iov;
9903db3f65cSamw 	t = &mbc->chain;
9913db3f65cSamw 	for (i = 0; i < iov_cnt; i++) {
9923db3f65cSamw 		MGET(m, M_WAIT, MT_DATA);
9933db3f65cSamw 		m->m_ext.ext_buf = iov->iov_base;
9943db3f65cSamw 		m->m_ext.ext_ref = smb_noop;
9953db3f65cSamw 		m->m_data = m->m_ext.ext_buf;
9963db3f65cSamw 		m->m_flags |= M_EXT;
9973db3f65cSamw 		m->m_len = m->m_ext.ext_size = iov->iov_len;
9983db3f65cSamw 		mbc->max_bytes += m->m_len;
9993db3f65cSamw 		m->m_next = 0;
10003db3f65cSamw 		*t = m;
10013db3f65cSamw 		t = &m->m_next;
10023db3f65cSamw 		iov++;
10033db3f65cSamw 	}
10043db3f65cSamw 	return (0);
10053db3f65cSamw }
10063db3f65cSamw 
10073db3f65cSamw static int
10083db3f65cSamw mbc_marshal_put_mbufs(mbuf_chain_t *mbc, mbuf_t *m)
10093db3f65cSamw {
10103db3f65cSamw 	mbuf_t	*mt;
10113db3f65cSamw 	mbuf_t	**t;
10123db3f65cSamw 	int	bytes;
10133db3f65cSamw 
10143db3f65cSamw 	if (m != NULL) {
10153db3f65cSamw 		mt = m;
10163db3f65cSamw 		bytes = mt->m_len;
10173db3f65cSamw 		while (mt->m_next != 0) {
10183db3f65cSamw 			mt = mt->m_next;
10193db3f65cSamw 			bytes += mt->m_len;
10203db3f65cSamw 		}
10213db3f65cSamw 		if (bytes != 0) {
10223db3f65cSamw 			t = &mbc->chain;
10233db3f65cSamw 			while (*t != 0) {
10243db3f65cSamw 				bytes += (*t)->m_len;
10253db3f65cSamw 				t = &(*t)->m_next;
10263db3f65cSamw 			}
10273db3f65cSamw 			*t = m;
10283db3f65cSamw 			mbc->chain_offset = bytes;
10293db3f65cSamw 		} else {
10303db3f65cSamw 			m_freem(m);
10313db3f65cSamw 		}
10323db3f65cSamw 	}
10333db3f65cSamw 	return (0);
10343db3f65cSamw }
10353db3f65cSamw 
10363db3f65cSamw static int
10373db3f65cSamw mbc_marshal_put_mbuf_chain(mbuf_chain_t *mbc, mbuf_chain_t *nmbc)
10383db3f65cSamw {
10393db3f65cSamw 	if (nmbc->chain != 0) {
10403db3f65cSamw 		if (mbc_marshal_put_mbufs(mbc, nmbc->chain))
10413db3f65cSamw 			return (DECODE_NO_MORE_DATA);
10423db3f65cSamw 		MBC_SETUP(nmbc, nmbc->max_bytes);
10433db3f65cSamw 	}
10443db3f65cSamw 	return (0);
10453db3f65cSamw }
10463db3f65cSamw 
10473db3f65cSamw static uint8_t
10483db3f65cSamw mbc_marshal_fetch_byte(mbuf_chain_t *mbc)
10493db3f65cSamw {
10503db3f65cSamw 	uint8_t	data;
10513db3f65cSamw 	mbuf_t	*m = mbc->chain;
10523db3f65cSamw 	int32_t	offset = mbc->chain_offset;
10533db3f65cSamw 
10543db3f65cSamw 	while (offset >= m->m_len) {
10553db3f65cSamw 		offset -= m->m_len;
10563db3f65cSamw 		m = m->m_next;
10573db3f65cSamw 	}
10583db3f65cSamw 	data = ((uint8_t *)m->m_data)[offset];
10593db3f65cSamw 	mbc->chain_offset++;
10603db3f65cSamw 	return (data);
10613db3f65cSamw }
10623db3f65cSamw 
10633db3f65cSamw static int
10643db3f65cSamw mbc_marshal_get_char(mbuf_chain_t *mbc, uint8_t *data)
10653db3f65cSamw {
10663db3f65cSamw 	if (MBC_ROOM_FOR(mbc, sizeof (char)) == 0) {
10673db3f65cSamw 		/* Data will never be available */
10683db3f65cSamw 		return (DECODE_NO_MORE_DATA);
10693db3f65cSamw 	}
10703db3f65cSamw 	*data = mbc_marshal_fetch_byte(mbc);
10713db3f65cSamw 	return (0);
10723db3f65cSamw }
10733db3f65cSamw 
10743db3f65cSamw static int
10753db3f65cSamw mbc_marshal_get_short(mbuf_chain_t *mbc, uint16_t *data)
10763db3f65cSamw {
10773db3f65cSamw 	uint16_t	tmp;
10783db3f65cSamw 	mbuf_t		*m = mbc->chain;
10793db3f65cSamw 	int32_t		offset = mbc->chain_offset;
10803db3f65cSamw 
10813db3f65cSamw 	if (MBC_ROOM_FOR(mbc, sizeof (short)) == 0) {
10823db3f65cSamw 		/* Data will never be available */
10833db3f65cSamw 		return (DECODE_NO_MORE_DATA);
10843db3f65cSamw 	}
10853db3f65cSamw 
10863db3f65cSamw 	while (offset >= m->m_len) {
10873db3f65cSamw 		offset -= m->m_len;
10883db3f65cSamw 		m = m->m_next;
10893db3f65cSamw 	}
10903db3f65cSamw 	if ((m->m_len - offset) >= sizeof (short)) {
10913db3f65cSamw 		*data = LE_IN16(m->m_data + offset);
10923db3f65cSamw 		mbc->chain_offset += sizeof (short);
10933db3f65cSamw 	} else {
10943db3f65cSamw 		tmp = (uint16_t)mbc_marshal_fetch_byte(mbc);
10953db3f65cSamw 		tmp |= ((uint16_t)mbc_marshal_fetch_byte(mbc)) << 8;
10963db3f65cSamw 		*data = tmp;
10973db3f65cSamw 	}
10983db3f65cSamw 	return (0);
10993db3f65cSamw }
11003db3f65cSamw 
11013db3f65cSamw static int
11023db3f65cSamw mbc_marshal_get_long(mbuf_chain_t *mbc, uint32_t *data)
11033db3f65cSamw {
11043db3f65cSamw 	uint32_t	tmp;
11053db3f65cSamw 	mbuf_t		*m = mbc->chain;
11063db3f65cSamw 	int32_t		offset = mbc->chain_offset;
11073db3f65cSamw 
11083db3f65cSamw 	if (MBC_ROOM_FOR(mbc, sizeof (int32_t)) == 0) {
11093db3f65cSamw 		/* Data will never be available */
11103db3f65cSamw 		return (DECODE_NO_MORE_DATA);
11113db3f65cSamw 	}
11123db3f65cSamw 	while (offset >= m->m_len) {
11133db3f65cSamw 		offset -= m->m_len;
11143db3f65cSamw 		m = m->m_next;
11153db3f65cSamw 	}
11163db3f65cSamw 	if ((m->m_len - offset) >= sizeof (int32_t)) {
11173db3f65cSamw 		*data = LE_IN32(m->m_data + offset);
11183db3f65cSamw 		mbc->chain_offset += sizeof (int32_t);
11193db3f65cSamw 	} else {
11203db3f65cSamw 		tmp = (uint32_t)mbc_marshal_fetch_byte(mbc);
11213db3f65cSamw 		tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 8;
11223db3f65cSamw 		tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 16;
11233db3f65cSamw 		tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 24;
11243db3f65cSamw 		*data = tmp;
11253db3f65cSamw 	}
11263db3f65cSamw 	return (0);
11273db3f65cSamw }
11283db3f65cSamw 
11293db3f65cSamw static uint64_t
11303db3f65cSamw qswap(uint64_t ll)
11313db3f65cSamw {
11323db3f65cSamw 	uint64_t v;
11333db3f65cSamw 
11343db3f65cSamw 	v = ll >> 32;
11353db3f65cSamw 	v |= ll << 32;
11363db3f65cSamw 
11373db3f65cSamw 	return (v);
11383db3f65cSamw }
11393db3f65cSamw 
11403db3f65cSamw static int
11413db3f65cSamw mbc_marshal_get_odd_long_long(mbuf_chain_t *mbc, uint64_t *data)
11423db3f65cSamw {
11433db3f65cSamw 	uint64_t	tmp;
11443db3f65cSamw 	mbuf_t		*m = mbc->chain;
11453db3f65cSamw 	int32_t		offset = mbc->chain_offset;
11463db3f65cSamw 
11473db3f65cSamw 	if (MBC_ROOM_FOR(mbc, sizeof (int64_t)) == 0) {
11483db3f65cSamw 		/* Data will never be available */
11493db3f65cSamw 		return (DECODE_NO_MORE_DATA);
11503db3f65cSamw 	}
11513db3f65cSamw 	while (offset >= m->m_len) {
11523db3f65cSamw 		offset -= m->m_len;
11533db3f65cSamw 		m = m->m_next;
11543db3f65cSamw 	}
11553db3f65cSamw 
11563db3f65cSamw 	if ((m->m_len - offset) >= sizeof (int64_t)) {
11573db3f65cSamw 		*data = qswap(LE_IN64(m->m_data + offset));
11583db3f65cSamw 		mbc->chain_offset += sizeof (int64_t);
11593db3f65cSamw 	} else {
11603db3f65cSamw 		tmp = (uint64_t)mbc_marshal_fetch_byte(mbc) << 32;
11613db3f65cSamw 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 40;
11623db3f65cSamw 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 48;
11633db3f65cSamw 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 56;
11643db3f65cSamw 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc);
11653db3f65cSamw 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 8;
11663db3f65cSamw 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 16;
11673db3f65cSamw 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 24;
11683db3f65cSamw 
11693db3f65cSamw 		*(uint64_t *)data = tmp;
11703db3f65cSamw 	}
11713db3f65cSamw 	return (0);
11723db3f65cSamw }
11733db3f65cSamw 
11743db3f65cSamw static int
11753db3f65cSamw mbc_marshal_get_long_long(mbuf_chain_t *mbc, uint64_t *data)
11763db3f65cSamw {
11773db3f65cSamw 	uint64_t	tmp;
11783db3f65cSamw 	mbuf_t		*m = mbc->chain;
11793db3f65cSamw 	int32_t		offset = mbc->chain_offset;
11803db3f65cSamw 
11813db3f65cSamw 	if (MBC_ROOM_FOR(mbc, sizeof (int64_t)) == 0) {
11823db3f65cSamw 		/* Data will never be available */
11833db3f65cSamw 		return (DECODE_NO_MORE_DATA);
11843db3f65cSamw 	}
11853db3f65cSamw 	while (offset >= m->m_len) {
11863db3f65cSamw 		offset -= m->m_len;
11873db3f65cSamw 		m = m->m_next;
11883db3f65cSamw 	}
11893db3f65cSamw 	if ((m->m_len - offset) >= sizeof (int64_t)) {
11903db3f65cSamw 		*data = LE_IN64(m->m_data + offset);
11913db3f65cSamw 		mbc->chain_offset += sizeof (int64_t);
11923db3f65cSamw 	} else {
11933db3f65cSamw 		tmp = (uint32_t)mbc_marshal_fetch_byte(mbc);
11943db3f65cSamw 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 8;
11953db3f65cSamw 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 16;
11963db3f65cSamw 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 24;
11973db3f65cSamw 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 32;
11983db3f65cSamw 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 40;
11993db3f65cSamw 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 48;
12003db3f65cSamw 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 56;
12013db3f65cSamw 		*(uint64_t *)data = tmp;
12023db3f65cSamw 	}
12033db3f65cSamw 	return (0);
12043db3f65cSamw }
12053db3f65cSamw 
12063db3f65cSamw /*
12073db3f65cSamw  * mbc_marshal_get_ascii_string
12083db3f65cSamw  *
12093db3f65cSamw  * The ascii string in smb includes oem chars. Since the
12103db3f65cSamw  * system needs utf8 encodes unicode char, conversion is
12113db3f65cSamw  * required to convert the oem char to unicode and then
12123db3f65cSamw  * to encode the converted wchars to utf8 format.
12133db3f65cSamw  * Therefore, the **ascii returned will be in such format
12143db3f65cSamw  * instead of the real ASCII format.
12153db3f65cSamw  */
12163db3f65cSamw static int
12173db3f65cSamw mbc_marshal_get_ascii_string(
1218bbf6f00cSJordan Brown     smb_request_t	*sr,
12193db3f65cSamw     mbuf_chain_t	*mbc,
12203db3f65cSamw     uint8_t		**ascii,
12213db3f65cSamw     int			max_ascii)
12223db3f65cSamw {
12233db3f65cSamw 	char		*rcvbuf;
12243db3f65cSamw 	char		*ch;
12253db3f65cSamw 	int		max;
12263db3f65cSamw 	int		length = 0;
12273db3f65cSamw 
12283db3f65cSamw 	max = MALLOC_QUANTUM;
1229bbf6f00cSJordan Brown 	rcvbuf = smb_srm_alloc(sr, max);
12303db3f65cSamw 
12313db3f65cSamw 	if (max_ascii == 0)
12323db3f65cSamw 		max_ascii = 0xffff;
12333db3f65cSamw 
12343db3f65cSamw 	ch = rcvbuf;
12353db3f65cSamw 	for (;;) {
12363db3f65cSamw 		while (length < max) {
12373db3f65cSamw 			if (max_ascii-- <= 0) {
12383db3f65cSamw 				*ch++ = 0;
12393db3f65cSamw 				goto multibyte_encode;
12403db3f65cSamw 			}
12413db3f65cSamw 			if (MBC_ROOM_FOR(mbc, sizeof (char)) == 0) {
12423db3f65cSamw 				/* Data will never be available */
12433db3f65cSamw 				return (DECODE_NO_MORE_DATA);
12443db3f65cSamw 			}
12453db3f65cSamw 			if ((*ch++ = mbc_marshal_fetch_byte(mbc)) == 0)
12463db3f65cSamw 				goto multibyte_encode;
12473db3f65cSamw 			length++;
12483db3f65cSamw 		}
12493db3f65cSamw 		max += MALLOC_QUANTUM;
1250bbf6f00cSJordan Brown 		rcvbuf = smb_srm_realloc(sr, rcvbuf, max);
12513db3f65cSamw 		ch = rcvbuf + length;
12523db3f65cSamw 	}
12533db3f65cSamw 
12543db3f65cSamw multibyte_encode:
12553db3f65cSamw 	/*
12563db3f65cSamw 	 * UTF-8 encode the string for internal system use.
12573db3f65cSamw 	 */
12583db3f65cSamw 	length = strlen(rcvbuf) + 1;
1259bbf6f00cSJordan Brown 	*ascii = smb_srm_alloc(sr, length * MTS_MB_CHAR_MAX);
1260e3f2c991SKeyur Desai 	return (mbc_marshal_cstou8("CP850", (char *)*ascii,
1261e3f2c991SKeyur Desai 	    (size_t)length * MTS_MB_CHAR_MAX, rcvbuf, (size_t)length));
12623db3f65cSamw }
12633db3f65cSamw 
12643db3f65cSamw static int
1265bbf6f00cSJordan Brown mbc_marshal_get_unicode_string(smb_request_t *sr,
12663db3f65cSamw     mbuf_chain_t *mbc, uint8_t **ascii, int max_unicode)
12673db3f65cSamw {
12683db3f65cSamw 	int		max;
12693db3f65cSamw 	uint16_t	wchar;
12703db3f65cSamw 	char		*ch;
12713db3f65cSamw 	int		emitted;
12723db3f65cSamw 	int		length = 0;
12733db3f65cSamw 
12743db3f65cSamw 	if (max_unicode == 0)
12753db3f65cSamw 		max_unicode = 0xffff;
12763db3f65cSamw 
12773db3f65cSamw 	max = MALLOC_QUANTUM;
1278bbf6f00cSJordan Brown 	*ascii = smb_srm_alloc(sr, max);
12793db3f65cSamw 
12803db3f65cSamw 	ch = (char *)*ascii;
12813db3f65cSamw 	for (;;) {
12823db3f65cSamw 		while ((length + MTS_MB_CHAR_MAX) < max) {
12833db3f65cSamw 			if (max_unicode <= 0)
12843db3f65cSamw 				goto done;
12853db3f65cSamw 			max_unicode -= 2;
12863db3f65cSamw 
12873db3f65cSamw 			if (mbc_marshal_get_short(mbc, &wchar) != 0)
12883db3f65cSamw 				return (DECODE_NO_MORE_DATA);
12893db3f65cSamw 
12903db3f65cSamw 			if (wchar == 0)	goto done;
12913db3f65cSamw 
1292bbf6f00cSJordan Brown 			emitted = smb_wctomb(ch, wchar);
12933db3f65cSamw 			length += emitted;
12943db3f65cSamw 			ch += emitted;
12953db3f65cSamw 		}
12963db3f65cSamw 		max += MALLOC_QUANTUM;
1297bbf6f00cSJordan Brown 		*ascii = smb_srm_realloc(sr, *ascii, max);
12983db3f65cSamw 		ch = (char *)*ascii + length;
12993db3f65cSamw 	}
13003db3f65cSamw done:	*ch = 0;
13013db3f65cSamw 	return (0);
13023db3f65cSamw }
13033db3f65cSamw 
13043db3f65cSamw static int /*ARGSUSED*/
13053db3f65cSamw mbc_marshal_get_mbufs(mbuf_chain_t *mbc, int32_t bytes, mbuf_t **m)
13063db3f65cSamw {
13073db3f65cSamw 	if (MBC_ROOM_FOR(mbc, bytes) == 0) {
13083db3f65cSamw 		/* Data will never be available */
13093db3f65cSamw 		return (DECODE_NO_MORE_DATA);
13103db3f65cSamw 	}
13113db3f65cSamw 	return (0);
13123db3f65cSamw }
13133db3f65cSamw 
13143db3f65cSamw static int
13153db3f65cSamw mbc_marshal_get_mbuf_chain(mbuf_chain_t *mbc, int32_t bytes, mbuf_chain_t *nmbc)
13163db3f65cSamw {
13173db3f65cSamw 	int	rc;
13183db3f65cSamw 	mbuf_t	*m;
13193db3f65cSamw 
13203db3f65cSamw 	if (bytes == 0) {
13213db3f65cSamw 		/* Get all the rest */
13223db3f65cSamw 		bytes = mbc->max_bytes - mbc->chain_offset;
13233db3f65cSamw 	}
13243db3f65cSamw 
13253db3f65cSamw 	MBC_SETUP(nmbc, mbc->max_bytes);
13263db3f65cSamw 	if ((rc = mbc_marshal_get_mbufs(mbc, bytes, &m)) != 0) {
13273db3f65cSamw 		if (m)
13283db3f65cSamw 			m_freem(m);
13293db3f65cSamw 		return (rc);
13303db3f65cSamw 	}
13313db3f65cSamw 	nmbc->chain = m;
13323db3f65cSamw 	while (m != 0) {
13333db3f65cSamw 		bytes += m->m_len;
13343db3f65cSamw 		m = m->m_next;
13353db3f65cSamw 	}
13363db3f65cSamw 	nmbc->max_bytes = bytes;
13373db3f65cSamw 	return (0);
13383db3f65cSamw }
13393db3f65cSamw 
13403db3f65cSamw static int
13413db3f65cSamw mbc_marshal_get_uio(mbuf_chain_t *mbc, struct uio *uio)
13423db3f65cSamw {
13433db3f65cSamw 	int		i, offset;
13443db3f65cSamw 	int32_t		bytes = uio->uio_resid;
13453db3f65cSamw 	int32_t		remainder;
13463db3f65cSamw 	struct iovec	*iov;
13473db3f65cSamw 	mbuf_t		*m;
13483db3f65cSamw 
13493db3f65cSamw 	/*
13503db3f65cSamw 	 * The residual count is tested because in the case of write requests
13513db3f65cSamw 	 * with no data (smbtorture RAW-WRITE test will generate that type of
13523db3f65cSamw 	 * request) this function is called with a residual count of zero
13533db3f65cSamw 	 * bytes.
13543db3f65cSamw 	 */
13557b6a044aSjose borrego 	if (bytes != 0) {
13563db3f65cSamw 		iov = uio->uio_iov;
13573db3f65cSamw 		uio->uio_segflg = UIO_SYSSPACE;
1358*f96bd5c8SAlan Wright 		uio->uio_extflg = UIO_COPY_DEFAULT;
13593db3f65cSamw 
13603db3f65cSamw 		if (MBC_ROOM_FOR(mbc, bytes) == 0) {
13613db3f65cSamw 			/* Data will never be available */
13623db3f65cSamw 			return (DECODE_NO_MORE_DATA);
13633db3f65cSamw 		}
13643db3f65cSamw 
13653db3f65cSamw 		m = mbc->chain;
13663db3f65cSamw 		offset = mbc->chain_offset;
13673db3f65cSamw 		while (offset >= m->m_len) {
13683db3f65cSamw 			offset -= m->m_len;
13693db3f65cSamw 			m = m->m_next;
13703db3f65cSamw 			ASSERT((offset == 0) || (offset && m));
13713db3f65cSamw 		}
13723db3f65cSamw 
13733db3f65cSamw 		for (i = 0; (bytes > 0) && (i < uio->uio_iovcnt); i++) {
13743db3f65cSamw 			iov[i].iov_base = &m->m_data[offset];
13753db3f65cSamw 			remainder = m->m_len - offset;
13763db3f65cSamw 			if (remainder >= bytes) {
13773db3f65cSamw 				iov[i].iov_len = bytes;
13783db3f65cSamw 				mbc->chain_offset += bytes;
13797b6a044aSjose borrego 				uio->uio_iovcnt = i + 1;
13807b6a044aSjose borrego 				return (0);
13813db3f65cSamw 			}
13823db3f65cSamw 			iov[i].iov_len = remainder;
13833db3f65cSamw 			mbc->chain_offset += remainder;
13843db3f65cSamw 			bytes -= remainder;
13853db3f65cSamw 			m = m->m_next;
13863db3f65cSamw 			offset = 0;
13873db3f65cSamw 		}
13883db3f65cSamw 		return (DECODE_NO_MORE_DATA);
13893db3f65cSamw 	}
13903db3f65cSamw 	return (0);
13913db3f65cSamw }
13923db3f65cSamw 
13933db3f65cSamw static int
13943db3f65cSamw mbc_marshal_get_skip(mbuf_chain_t *mbc, uint_t skip)
13953db3f65cSamw {
13963db3f65cSamw 	if (MBC_ROOM_FOR(mbc, skip) == 0)
13973db3f65cSamw 		return (DECODE_NO_MORE_DATA);
13983db3f65cSamw 	mbc->chain_offset += skip;
13993db3f65cSamw 	return (0);
14003db3f65cSamw }
1401e3f2c991SKeyur Desai 
1402e3f2c991SKeyur Desai /*
1403e3f2c991SKeyur Desai  * Converts oem string to UTF-8 string with an output string of max
1404e3f2c991SKeyur Desai  * maxconv bytes.  The string may be truncated or not null-terminated if
1405e3f2c991SKeyur Desai  * there is not enough room.
1406e3f2c991SKeyur Desai  *
1407e3f2c991SKeyur Desai  * returns -1, cnt (partial conversion)  or 0 (success)
1408e3f2c991SKeyur Desai  */
1409e3f2c991SKeyur Desai 
1410e3f2c991SKeyur Desai static int
1411e3f2c991SKeyur Desai mbc_marshal_cstou8(char *cs, char *outbuf, size_t maxconv,
1412e3f2c991SKeyur Desai     char *inbuf, size_t srcbytes)
1413e3f2c991SKeyur Desai {
1414e3f2c991SKeyur Desai 	kiconv_t	t2u;
1415e3f2c991SKeyur Desai 	size_t		inlen = srcbytes;
1416e3f2c991SKeyur Desai 	size_t		outlen = maxconv;
1417e3f2c991SKeyur Desai 	int		err = 0;
1418e3f2c991SKeyur Desai 	size_t		rc;
1419e3f2c991SKeyur Desai 
1420e3f2c991SKeyur Desai 	if ((t2u = kiconv_open("UTF-8", cs)) == (kiconv_t)-1)
1421e3f2c991SKeyur Desai 		return (-1);
1422e3f2c991SKeyur Desai 
1423e3f2c991SKeyur Desai 	rc = kiconv(t2u, &inbuf, &inlen, &outbuf, &outlen, &err);
1424e3f2c991SKeyur Desai 	(void) kiconv_close(t2u);
1425e3f2c991SKeyur Desai 	return ((int)rc);
1426e3f2c991SKeyur Desai }
1427