xref: /illumos-gate/usr/src/uts/common/fs/smbsrv/smb_mbuf_marshaling.c (revision 897907ce12f040adf70d35697d537c9d72b35285)
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 /*
22f96bd5c8SAlan Wright  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23da6c28aaSamw  * Use is subject to license terms.
2412b65585SGordon Ross  *
25*897907ceSGordon Ross  * Copyright 2013-2021 Tintri by DDN, Inc. All rights reserved.
26da6c28aaSamw  */
27da6c28aaSamw 
28da6c28aaSamw /*
29da6c28aaSamw  * SMB mbuf marshaling encode/decode.
30da6c28aaSamw  */
31da6c28aaSamw 
32bbf6f00cSJordan Brown #include <smbsrv/smb_kproto.h>
33e3f2c991SKeyur Desai 
34e3f2c991SKeyur Desai 
35da6c28aaSamw #define	MALLOC_QUANTUM	80
36da6c28aaSamw 
37da6c28aaSamw #define	DECODE_NO_ERROR		0
38da6c28aaSamw #define	DECODE_NO_MORE_DATA	1
39da6c28aaSamw #define	DECODE_ALLOCATION_ERROR	2
40da6c28aaSamw #define	DECODE_CONVERSION_ERROR	3
41da6c28aaSamw 
423db3f65cSamw static int mbc_marshal_make_room(mbuf_chain_t *, int32_t);
433db3f65cSamw static void mbc_marshal_store_byte(mbuf_chain_t *, uint8_t);
443db3f65cSamw static int mbc_marshal_put_char(mbuf_chain_t *mbc, uint8_t);
453db3f65cSamw static int mbc_marshal_put_short(mbuf_chain_t *mbc, uint16_t);
463db3f65cSamw static int mbc_marshal_put_long(mbuf_chain_t *mbc, uint32_t);
473db3f65cSamw static int mbc_marshal_put_long_long(mbuf_chain_t *mbc, uint64_t);
487d1ffc32SGordon Ross static int mbc_marshal_put_oem_string(mbuf_chain_t *, char *, int);
493db3f65cSamw static int mbc_marshal_put_unicode_string(mbuf_chain_t *, char *, int);
503db3f65cSamw static int mbc_marshal_put_uio(mbuf_chain_t *, struct uio *);
513db3f65cSamw static int mbc_marshal_put_mbufs(mbuf_chain_t *mbc, mbuf_t *m);
523db3f65cSamw static int mbc_marshal_put_mbuf_chain(mbuf_chain_t *mbc, mbuf_chain_t *nmbc);
533db3f65cSamw static uint8_t mbc_marshal_fetch_byte(mbuf_chain_t *mbc);
543db3f65cSamw static int mbc_marshal_get_char(mbuf_chain_t *mbc, uint8_t *data);
553db3f65cSamw static int mbc_marshal_get_short(mbuf_chain_t *mbc, uint16_t *data);
563db3f65cSamw static int mbc_marshal_get_long(mbuf_chain_t *mbc, uint32_t *data);
573db3f65cSamw static uint64_t qswap(uint64_t ll);
583db3f65cSamw static int mbc_marshal_get_odd_long_long(mbuf_chain_t *mbc, uint64_t *data);
593db3f65cSamw static int mbc_marshal_get_long_long(mbuf_chain_t *mbc, uint64_t *data);
6007a6ae61SGordon Ross static int mbc_marshal_get_oem_string(smb_request_t *, mbuf_chain_t *,
6107a6ae61SGordon Ross     char **, int);
62bbf6f00cSJordan Brown static int mbc_marshal_get_unicode_string(smb_request_t *, mbuf_chain_t *,
6307a6ae61SGordon Ross     char **, int);
643db3f65cSamw static int mbc_marshal_get_mbufs(mbuf_chain_t *, int32_t, mbuf_t **);
653db3f65cSamw static int mbc_marshal_get_mbuf_chain(mbuf_chain_t *, int32_t, mbuf_chain_t *);
663db3f65cSamw static int mbc_marshal_get_uio(mbuf_chain_t *, struct uio *);
673db3f65cSamw static int mbc_marshal_get_skip(mbuf_chain_t *, uint_t);
68da6c28aaSamw 
69da6c28aaSamw /*
703db3f65cSamw  * smb_mbc_vdecodef
71da6c28aaSamw  *
723db3f65cSamw  * This function reads the contents of the mbc chain passed in under the list
733db3f65cSamw  * of arguments passed in.
74da6c28aaSamw  *
75da6c28aaSamw  * The format string provides a description of the parameters passed in as well
763db3f65cSamw  * as an action to be taken by smb_mbc_vdecodef().
77da6c28aaSamw  *
78da6c28aaSamw  *	%	Pointer to an SMB request structure (smb_request_t *). There
79da6c28aaSamw  *		should be only one of these in the string.
80da6c28aaSamw  *
81da6c28aaSamw  *	C	Pointer to an mbuf chain. Copy to that mbuf chain the number of
82da6c28aaSamw  *		bytes specified (number preceding C).
83da6c28aaSamw  *
84da6c28aaSamw  *	m	Pointer to an mbuf. Copy to that mbuf the number of bytes
85da6c28aaSamw  *		specified (number preceding m).
86da6c28aaSamw  *
87da6c28aaSamw  *	M	Read the 32 bit value at the current location of the mbuf chain
88a90cf9f2SGordon Ross  *		and check if it matches the signature of an SMB1 request (SMBx).
89a90cf9f2SGordon Ross  *
90a90cf9f2SGordon Ross  *	N	Read the 32 bit value at the current location of the mbuf chain
91a90cf9f2SGordon Ross  *		and check if it matches the signature of an SMB2 request (SMBx).
92da6c28aaSamw  *
93da6c28aaSamw  *	b	Pointer to a buffer. Copy to that buffer the number of bytes
94da6c28aaSamw  *		specified (number preceding b).
95da6c28aaSamw  *
96da6c28aaSamw  *	c	Same as 'b'.
97da6c28aaSamw  *
98da6c28aaSamw  *	w	Pointer to a word (16bit value). Copy the next 16bit value into
99da6c28aaSamw  *		that location.
100da6c28aaSamw  *
101da6c28aaSamw  *	l	Pointer to a long (32bit value). Copy the next 32bit value into
102da6c28aaSamw  *		that location.
103da6c28aaSamw  *
104da6c28aaSamw  *	q	Pointer to a quad (64bit value). Copy the next 64bit value into
105da6c28aaSamw  *		that location.
106da6c28aaSamw  *
107da6c28aaSamw  *	Q	Same as above with a call to qswap().
108da6c28aaSamw  *
109da6c28aaSamw  *	B	Pointer to a vardata_block structure. That structure is used to
110da6c28aaSamw  *		retrieve data from the mbuf chain (an iovec type structure is
111da6c28aaSamw  *		embedded in a vardata_block).
112da6c28aaSamw  *
113da6c28aaSamw  *	D	Pointer to a vardata_block structure. That structure is used to
114da6c28aaSamw  *		retrieve data from the mbuf chain, however, two fields of the
115da6c28aaSamw  *		vardata_block structure (tag and len) are first initialized
116da6c28aaSamw  *		using the mbuf chain itself.
117da6c28aaSamw  *
118da6c28aaSamw  *	V	Same as 'D'.
119da6c28aaSamw  *
120da6c28aaSamw  *	L
121da6c28aaSamw  *
122da6c28aaSamw  *	A
123da6c28aaSamw  *
124da6c28aaSamw  *	P	Same as 'A'
125da6c28aaSamw  *
126da6c28aaSamw  *	S	Same as 'A'
127da6c28aaSamw  *
128da6c28aaSamw  *	u	Pointer to a string pointer. Allocate memory and retrieve the
129da6c28aaSamw  *		string at the current location in the mbuf chain. Store the
130da6c28aaSamw  *		address to the buffer allocated at the address specified by
131da6c28aaSamw  *		the pointer. In addition if an sr was passed and it indicates
132da6c28aaSamw  *		that the string is an unicode string, convert it.
133da6c28aaSamw  *
134da6c28aaSamw  *	s	Same as 'u' without convertion.
135da6c28aaSamw  *
136da6c28aaSamw  *	U	Same as 'u'. The string to retrieve is unicode.
137da6c28aaSamw  *
138da6c28aaSamw  *	y	Pointer to a 32bit value. Read the dos time at the current mbuf
139da6c28aaSamw  *		chain location, convert it to unix time and store it at the
140da6c28aaSamw  *		location indicated by the pointer.
141da6c28aaSamw  *
142da6c28aaSamw  *	Y	Same as 'y' bt the dos time coded in the mbuf chain is inverted.
143da6c28aaSamw  *
144da6c28aaSamw  *	.	Skip the number of bytes indicated by the number preceding '.'.
145da6c28aaSamw  *
146da6c28aaSamw  *	,	Same as '.' but take in account it is an unicode string.
147da6c28aaSamw  */
148da6c28aaSamw int
smb_mbc_vdecodef(mbuf_chain_t * mbc,const char * fmt,va_list ap)149a90cf9f2SGordon Ross smb_mbc_vdecodef(mbuf_chain_t *mbc, const char *fmt, va_list ap)
150da6c28aaSamw {
1513db3f65cSamw 	uint8_t		c;
1523db3f65cSamw 	uint8_t		cval;
1533db3f65cSamw 	uint8_t		*cvalp;
15407a6ae61SGordon Ross 	char		**charpp;
1552c2961f8Sjose borrego 	uint16_t	wval;
1563db3f65cSamw 	uint16_t	*wvalp;
157da6c28aaSamw 	uint32_t	*lvalp;
158da6c28aaSamw 	uint64_t	*llvalp;
1593db3f65cSamw 	smb_vdb_t	*vdp;
1603db3f65cSamw 	smb_request_t	*sr = NULL;
161da6c28aaSamw 	uint32_t	lval;
162da6c28aaSamw 	int		unicode = 0;
163da6c28aaSamw 	int		repc;
16412b65585SGordon Ross 	boolean_t	repc_specified;
165da6c28aaSamw 
166da6c28aaSamw 	while ((c = *fmt++) != 0) {
16712b65585SGordon Ross 		repc_specified = B_FALSE;
168da6c28aaSamw 		repc = 1;
169da6c28aaSamw 
170da6c28aaSamw 		if ('0' <= c && c <= '9') {
171da6c28aaSamw 			repc = 0;
172da6c28aaSamw 			do {
173da6c28aaSamw 				repc = repc * 10 + c - '0';
174da6c28aaSamw 				c = *fmt++;
175da6c28aaSamw 			} while ('0' <= c && c <= '9');
17612b65585SGordon Ross 			repc_specified = B_TRUE;
177da6c28aaSamw 		} else if (c == '#') {
178da6c28aaSamw 			repc = va_arg(ap, int);
179da6c28aaSamw 			c = *fmt++;
18012b65585SGordon Ross 			repc_specified = B_TRUE;
181da6c28aaSamw 		}
182da6c28aaSamw 
183da6c28aaSamw 		switch (c) {
184da6c28aaSamw 		case '%':
185da6c28aaSamw 			sr = va_arg(ap, struct smb_request *);
186a90cf9f2SGordon Ross 			if (sr->session->dialect >= SMB_VERS_2_BASE) {
187a90cf9f2SGordon Ross 				unicode = 1;
188a90cf9f2SGordon Ross 				break;
189a90cf9f2SGordon Ross 			}
190da6c28aaSamw 			unicode = sr->smb_flg2 & SMB_FLAGS2_UNICODE;
191da6c28aaSamw 			break;
192da6c28aaSamw 
193da6c28aaSamw 		case 'C':	/* Mbuf_chain */
194da6c28aaSamw 			if (mbc_marshal_get_mbuf_chain(mbc, repc,
1953db3f65cSamw 			    va_arg(ap, mbuf_chain_t *)) != 0)
1963db3f65cSamw 				return (-1);
197da6c28aaSamw 			break;
198da6c28aaSamw 
199da6c28aaSamw 		case 'm':	/* struct_mbuf */
200da6c28aaSamw 			if (mbc_marshal_get_mbufs(mbc, repc,
2013db3f65cSamw 			    va_arg(ap, mbuf_t **)) != 0)
2023db3f65cSamw 				return (-1);
203da6c28aaSamw 			break;
204da6c28aaSamw 
205da6c28aaSamw 		case 'M':
2063db3f65cSamw 			if (mbc_marshal_get_long(mbc, &lval) != 0)
2073db3f65cSamw 				return (-1);
208da6c28aaSamw 			if (lval != 0x424D53FF) /* 0xFF S M B */
2093db3f65cSamw 				return (-1);
210da6c28aaSamw 			break;
211da6c28aaSamw 
212a90cf9f2SGordon Ross 		case 'N':
213a90cf9f2SGordon Ross 			if (mbc_marshal_get_long(mbc, &lval) != 0)
214a90cf9f2SGordon Ross 				return (-1);
215a90cf9f2SGordon Ross 			if (lval != 0x424D53FE) /* 0xFE S M B */
216a90cf9f2SGordon Ross 				return (-1);
217a90cf9f2SGordon Ross 			break;
218a90cf9f2SGordon Ross 
219da6c28aaSamw 		case 'b':
220da6c28aaSamw 		case 'c':
2213db3f65cSamw 			cvalp = va_arg(ap, uint8_t *);
2223db3f65cSamw 			if (MBC_ROOM_FOR(mbc, repc) == 0)
223da6c28aaSamw 				/* Data will never be available */
2243db3f65cSamw 				return (-1);
2253db3f65cSamw 
226da6c28aaSamw 			while (repc-- > 0)
227da6c28aaSamw 				*cvalp++ = mbc_marshal_fetch_byte(mbc);
228da6c28aaSamw 			break;
229da6c28aaSamw 
230da6c28aaSamw 		case 'w':
2313db3f65cSamw 			wvalp = va_arg(ap, uint16_t *);
232da6c28aaSamw 			while (repc-- > 0)
233da6c28aaSamw 				if (mbc_marshal_get_short(mbc, wvalp++) != 0)
2343db3f65cSamw 					return (-1);
235da6c28aaSamw 			break;
236da6c28aaSamw 
237da6c28aaSamw 		case 'l':
238da6c28aaSamw 			lvalp = va_arg(ap, uint32_t *);
239da6c28aaSamw 			while (repc-- > 0)
240da6c28aaSamw 				if (mbc_marshal_get_long(mbc, lvalp++) != 0)
2413db3f65cSamw 					return (-1);
242da6c28aaSamw 			break;
243da6c28aaSamw 
244da6c28aaSamw 		case 'q':
245da6c28aaSamw 			llvalp = va_arg(ap, uint64_t *);
246da6c28aaSamw 			while (repc-- > 0)
247da6c28aaSamw 				if (mbc_marshal_get_long_long(
248da6c28aaSamw 				    mbc, llvalp++) != 0)
2493db3f65cSamw 					return (-1);
250da6c28aaSamw 			break;
251da6c28aaSamw 
252da6c28aaSamw 		case 'Q':
253da6c28aaSamw 			llvalp = va_arg(ap, uint64_t *);
254da6c28aaSamw 			while (repc-- > 0)
255da6c28aaSamw 				if (mbc_marshal_get_odd_long_long(
256da6c28aaSamw 				    mbc, llvalp++) != 0)
2573db3f65cSamw 					return (-1);
258da6c28aaSamw 			break;
259da6c28aaSamw 
260da6c28aaSamw 		case 'B':
261da6c28aaSamw 			vdp = va_arg(ap, struct vardata_block *);
2622c2961f8Sjose borrego 			vdp->vdb_tag = 0;
2632c2961f8Sjose borrego 			vdp->vdb_len = repc;
2642c2961f8Sjose borrego 			vdp->vdb_uio.uio_iov = &vdp->vdb_iovec[0];
2652c2961f8Sjose borrego 			vdp->vdb_uio.uio_iovcnt = MAX_IOVEC;
266f96bd5c8SAlan Wright 			vdp->vdb_uio.uio_extflg = UIO_COPY_DEFAULT;
2672c2961f8Sjose borrego 			vdp->vdb_uio.uio_resid = repc;
2682c2961f8Sjose borrego 			if (mbc_marshal_get_uio(mbc, &vdp->vdb_uio) != 0)
2693db3f65cSamw 				return (-1);
270da6c28aaSamw 			break;
271da6c28aaSamw 
2723db3f65cSamw 		case 'D':
2733db3f65cSamw 		case 'V':
274da6c28aaSamw 			vdp = va_arg(ap, struct vardata_block *);
2752c2961f8Sjose borrego 			if (mbc_marshal_get_char(mbc, &vdp->vdb_tag) != 0)
2763db3f65cSamw 				return (-1);
2772c2961f8Sjose borrego 			if (mbc_marshal_get_short(mbc, &wval) != 0)
2783db3f65cSamw 				return (-1);
2792c2961f8Sjose borrego 			vdp->vdb_len = (uint32_t)wval;
2802c2961f8Sjose borrego 			vdp->vdb_uio.uio_iov = &vdp->vdb_iovec[0];
2812c2961f8Sjose borrego 			vdp->vdb_uio.uio_iovcnt = MAX_IOVEC;
282f96bd5c8SAlan Wright 			vdp->vdb_uio.uio_extflg = UIO_COPY_DEFAULT;
2832c2961f8Sjose borrego 			vdp->vdb_uio.uio_resid = vdp->vdb_len;
2842c2961f8Sjose borrego 			if (vdp->vdb_len != 0) {
2852c2961f8Sjose borrego 				if (mbc_marshal_get_uio(mbc,
2862c2961f8Sjose borrego 				    &vdp->vdb_uio) != 0)
2873db3f65cSamw 					return (-1);
288da6c28aaSamw 			}
289da6c28aaSamw 			break;
290da6c28aaSamw 
291da6c28aaSamw 		case 'L':
292da6c28aaSamw 			if (mbc_marshal_get_char(mbc, &cval) != 0)
2933db3f65cSamw 				return (-1);
294da6c28aaSamw 			if (cval != 2)
2953db3f65cSamw 				return (-1);
29607a6ae61SGordon Ross 			goto oem_conversion;
297da6c28aaSamw 
2983db3f65cSamw 		case 'A':
2993db3f65cSamw 		case 'S':
300da6c28aaSamw 			if (mbc_marshal_get_char(mbc, &cval) != 0)
3013db3f65cSamw 				return (-1);
302da6c28aaSamw 			if (((c == 'A' || c == 'S') && cval != 4) ||
3033db3f65cSamw 			    (c == 'L' && cval != 2))
3043db3f65cSamw 				return (-1);
305da6c28aaSamw 			/* FALLTHROUGH */
306da6c28aaSamw 
307da6c28aaSamw 		case 'u': /* Convert from unicode if flags are set */
308da6c28aaSamw 			if (unicode)
309da6c28aaSamw 				goto unicode_translation;
310da6c28aaSamw 			/* FALLTHROUGH */
311da6c28aaSamw 
3127d1ffc32SGordon Ross 		case 's':	/* get OEM string */
31307a6ae61SGordon Ross oem_conversion:
314da6c28aaSamw 			ASSERT(sr != NULL);
31507a6ae61SGordon Ross 			charpp = va_arg(ap, char **);
31612b65585SGordon Ross 			if (!repc_specified)
317da6c28aaSamw 				repc = 0;
31807a6ae61SGordon Ross 			if (mbc_marshal_get_oem_string(sr,
31907a6ae61SGordon Ross 			    mbc, charpp, repc) != 0)
3203db3f65cSamw 				return (-1);
321da6c28aaSamw 			break;
322da6c28aaSamw 
3237d1ffc32SGordon Ross 		case 'U':	/* get UTF-16 string */
324da6c28aaSamw unicode_translation:
325da6c28aaSamw 			ASSERT(sr != 0);
32607a6ae61SGordon Ross 			charpp = va_arg(ap, char **);
32712b65585SGordon Ross 			if (!repc_specified)
328da6c28aaSamw 				repc = 0;
329bbf6f00cSJordan Brown 			if (mbc_marshal_get_unicode_string(sr,
33007a6ae61SGordon Ross 			    mbc, charpp, repc) != 0)
3313db3f65cSamw 				return (-1);
332da6c28aaSamw 			break;
333da6c28aaSamw 
334da6c28aaSamw 		case 'Y': /* dos time to unix time tt/dd */
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 *)&t) != 0)
3413db3f65cSamw 					return (-1);
342da6c28aaSamw 				if (mbc_marshal_get_short(mbc,
3433db3f65cSamw 				    (uint16_t *)&d) != 0)
3443db3f65cSamw 					return (-1);
345e3f2c991SKeyur Desai 				*lvalp++ = smb_time_dos_to_unix(d, t);
346da6c28aaSamw 			}
347da6c28aaSamw 			break;
348da6c28aaSamw 
349da6c28aaSamw 		case 'y': /* dos time to unix time dd/tt */
350da6c28aaSamw 			lvalp = va_arg(ap, uint32_t *);
351da6c28aaSamw 			while (repc-- > 0) {
352da6c28aaSamw 				short	d, t;
353da6c28aaSamw 
354da6c28aaSamw 				if (mbc_marshal_get_short(mbc,
3553db3f65cSamw 				    (uint16_t *)&d) != 0)
3563db3f65cSamw 					return (-1);
357da6c28aaSamw 				if (mbc_marshal_get_short(mbc,
3583db3f65cSamw 				    (uint16_t *)&t) != 0)
3593db3f65cSamw 					return (-1);
360e3f2c991SKeyur Desai 				*lvalp++ = smb_time_dos_to_unix(d, t);
361da6c28aaSamw 			}
362da6c28aaSamw 			break;
363da6c28aaSamw 
364da6c28aaSamw 		case ',':
365da6c28aaSamw 			if (unicode)
366da6c28aaSamw 				repc *= 2;
367da6c28aaSamw 			/* FALLTHROUGH */
368da6c28aaSamw 
369da6c28aaSamw 		case '.':
370da6c28aaSamw 			if (mbc_marshal_get_skip(mbc, repc) != 0)
3713db3f65cSamw 				return (-1);
372da6c28aaSamw 			break;
3733db3f65cSamw 
3743db3f65cSamw 		default:
3753db3f65cSamw 			ASSERT(0);
3763db3f65cSamw 			return (-1);
377da6c28aaSamw 		}
378da6c28aaSamw 	}
379da6c28aaSamw 	return (0);
380da6c28aaSamw }
381da6c28aaSamw 
3823db3f65cSamw /*
3833db3f65cSamw  * smb_mbc_decodef
3843db3f65cSamw  *
3853db3f65cSamw  * This function reads the contents of the mbc chain passed in under the
3863db3f65cSamw  * control of the format fmt.
3873db3f65cSamw  *
3883db3f65cSamw  * (for a description of the format string see smb_mbc_vencodef()).
3893db3f65cSamw  */
390da6c28aaSamw int
smb_mbc_decodef(mbuf_chain_t * mbc,const char * fmt,...)391a90cf9f2SGordon Ross smb_mbc_decodef(mbuf_chain_t *mbc, const char *fmt, ...)
392da6c28aaSamw {
393da6c28aaSamw 	int	xx;
394da6c28aaSamw 	va_list	ap;
395da6c28aaSamw 
396da6c28aaSamw 	va_start(ap, fmt);
3973db3f65cSamw 	xx = smb_mbc_vdecodef(mbc, fmt, ap);
398da6c28aaSamw 	va_end(ap);
399da6c28aaSamw 	return (xx);
400da6c28aaSamw }
401da6c28aaSamw 
4023db3f65cSamw /*
4033db3f65cSamw  * smb_mbc_peek
4043db3f65cSamw  *
4053db3f65cSamw  * This function reads the contents of the mbc passed in at the specified offset
4063db3f65cSamw  * under the control of the format fmt. The offset of the chain passed in is not
4073db3f65cSamw  * modified.
4083db3f65cSamw  *
4093db3f65cSamw  * (for a description of the format string see smb_mbc_vdecodef()).
4103db3f65cSamw  */
411da6c28aaSamw int
smb_mbc_peek(mbuf_chain_t * mbc,int offset,const char * fmt,...)412a90cf9f2SGordon Ross smb_mbc_peek(mbuf_chain_t *mbc, int offset, const char *fmt, ...)
413da6c28aaSamw {
4143db3f65cSamw 	mbuf_chain_t	tmp;
415da6c28aaSamw 	va_list		ap;
4163db3f65cSamw 	int		xx;
417da6c28aaSamw 
418da6c28aaSamw 	va_start(ap, fmt);
419da6c28aaSamw 
4203db3f65cSamw 	(void) MBC_SHADOW_CHAIN(&tmp, mbc, offset, mbc->max_bytes - offset);
4213db3f65cSamw 	xx = smb_mbc_vdecodef(&tmp, fmt, ap);
422da6c28aaSamw 	va_end(ap);
4233db3f65cSamw 	return (xx);
424da6c28aaSamw }
425da6c28aaSamw 
426da6c28aaSamw /*
4273db3f65cSamw  * smb_mbc_vencodef
4283db3f65cSamw  *
4293db3f65cSamw  * This function builds a stream of bytes in the mbc chain passed in under the
4303db3f65cSamw  * control of the list of arguments passed in.
431da6c28aaSamw  *
432da6c28aaSamw  * The format string provides a description of the parameters passed in as well
4333db3f65cSamw  * as an action to be taken by smb_mbc_vencodef().
434da6c28aaSamw  *
435da6c28aaSamw  *	\b	Restore the mbuf chain offset to its initial value.
436da6c28aaSamw  *
437da6c28aaSamw  *	%	Pointer to an SMB request structure (smb_request_t *). There
438da6c28aaSamw  *		should be only one of these in the string. If an sr in present
439da6c28aaSamw  *		it will be used to determine if unicode conversion should be
440da6c28aaSamw  *		applied to the strings.
441da6c28aaSamw  *
442da6c28aaSamw  *	C	Pointer to an mbuf chain. Copy that mbuf chain into the
443da6c28aaSamw  *		destination mbuf chain.
444da6c28aaSamw  *
445da6c28aaSamw  *	D	Pointer to a vardata_block structure. Copy the data described
446da6c28aaSamw  *		by that structure into the mbuf chain. The tag field is hard
447da6c28aaSamw  *		coded to '1'.
448da6c28aaSamw  *
449a90cf9f2SGordon Ross  *	M	Write the SMB1 request signature ('SMBX') into the mbuf chain.
450a90cf9f2SGordon Ross  *
451a90cf9f2SGordon Ross  *	N	Write the SMB2 request signature ('SMBX') into the mbuf chain.
452da6c28aaSamw  *
453da6c28aaSamw  *	T	Pointer to a timestruc_t. Convert the content of the structure
454da6c28aaSamw  *		into NT time and store the result of the conversion in the
455da6c28aaSamw  *		mbuf chain.
456da6c28aaSamw  *
457da6c28aaSamw  *	V	Same as 'D' but the tag field is hard coded to '5'.
458da6c28aaSamw  *
459da6c28aaSamw  *	b	Byte. Store the byte or the nymber of bytes specified into the
460da6c28aaSamw  *		the mbuf chain. A format string like this "2b" would require 2
461da6c28aaSamw  *		bytes to be passed in.
462da6c28aaSamw  *
463da6c28aaSamw  *	m	Pointer to an mbuf. Copy the contents of the mbuf into the mbuf
464da6c28aaSamw  *		chain.
465da6c28aaSamw  *
466da6c28aaSamw  *	c	Pointer to a buffer. Copy the buffer into the mbuf chain. The
467da6c28aaSamw  *		size of the buffer is indicated by the number preceding 'c'.
468da6c28aaSamw  *
469da6c28aaSamw  *	w	Word (16bit value). Store the word or the number of words
470da6c28aaSamw  *              specified into the the mbuf chain. A format string like this
471da6c28aaSamw  *		"2w" would require 2 words to be passed in.
472da6c28aaSamw  *
473da6c28aaSamw  *	l	Long (32bit value). Store the long or the number of longs
474da6c28aaSamw  *		specified into the the mbuf chain. A format string like this
475da6c28aaSamw  *		"2l" would require 2 longs to be passed in.
476da6c28aaSamw  *
477da6c28aaSamw  *	q	Quad (64bit value). Store the quad or the number of quads
478da6c28aaSamw  *		specified into the the mbuf chain. A format string like this
479da6c28aaSamw  *		"2q" would require 2 quads to be passed in.
480da6c28aaSamw  *
481da6c28aaSamw  *	L	Pointer to a string. Store the string passed in into the mbuf
482da6c28aaSamw  *		chain preceded with a tag value of '2'.
483da6c28aaSamw  *
484da6c28aaSamw  *	S	Pointer to a string. Store the string passed in into the mbuf
485da6c28aaSamw  *		chain preceded with a tag value of '4'. Applied a unicode
486da6c28aaSamw  *		conversion is appropriate.
487da6c28aaSamw  *
488da6c28aaSamw  *	A	Same as 'S'
489da6c28aaSamw  *
490da6c28aaSamw  *	P	Pointer to a string. Store the string passed in into the mbuf
491da6c28aaSamw  *		chain preceded with a tag value of '5'. Applied a unicode
492da6c28aaSamw  *		conversion is appropriate.
493da6c28aaSamw  *
494da6c28aaSamw  *	u	Pointer to a string. Store the string passed in into the mbuf
495da6c28aaSamw  *		chain. Applied a unicode conversion is appropriate.
496da6c28aaSamw  *
497da6c28aaSamw  *	s	Pointer to a string. Store the string passed in into the mbuf
498da6c28aaSamw  *		chain.
499da6c28aaSamw  *
500da6c28aaSamw  *	Y	Date/Time.  Store the Date/Time or the number of Date/Time(s)
501da6c28aaSamw  *		specified into the the mbuf chain. A format string like this
502da6c28aaSamw  *		"2Y" would require 2 Date/Time values. The Date/Time is
503da6c28aaSamw  *		converted to DOS before storing.
504da6c28aaSamw  *
505da6c28aaSamw  *	y	Same as 'Y'. The order of Date and Time is reversed.
506da6c28aaSamw  *
507da6c28aaSamw  *	,	Character. Store the character or number of character specified
508da6c28aaSamw  *		into the mbuf chain.  A format string like this "2c" would
509da6c28aaSamw  *		require 2 characters to be passed in. A unicode conversion is
510da6c28aaSamw  *		applied if appropriate.
511da6c28aaSamw  *
512da6c28aaSamw  *	.	Same as '`' without unicode conversion.
513da6c28aaSamw  *
514da6c28aaSamw  *	U	Align the offset of the mbuf chain on a 16bit boundary.
515da6c28aaSamw  */
516da6c28aaSamw int
smb_mbc_vencodef(mbuf_chain_t * mbc,const char * fmt,va_list ap)517a90cf9f2SGordon Ross smb_mbc_vencodef(mbuf_chain_t *mbc, const char *fmt, va_list ap)
518da6c28aaSamw {
51907a6ae61SGordon Ross 	char		*charp;
5203db3f65cSamw 	uint8_t		*cvalp;
521da6c28aaSamw 	timestruc_t	*tvp;
5223db3f65cSamw 	smb_vdb_t	*vdp;
5233db3f65cSamw 	smb_request_t	*sr = NULL;
5243db3f65cSamw 	uint64_t	llval;
525da6c28aaSamw 	int64_t		nt_time;
5263db3f65cSamw 	uint32_t	lval;
5273db3f65cSamw 	uint_t		tag;
528da6c28aaSamw 	int		unicode = 0;
52912b65585SGordon Ross 	int		repc;
53012b65585SGordon Ross 	boolean_t	repc_specified;
5313db3f65cSamw 	uint16_t	wval;
5323db3f65cSamw 	uint8_t		cval;
5333db3f65cSamw 	uint8_t		c;
534da6c28aaSamw 
535da6c28aaSamw 	while ((c = *fmt++) != 0) {
53612b65585SGordon Ross 		repc_specified = B_FALSE;
537da6c28aaSamw 		repc = 1;
538da6c28aaSamw 
539da6c28aaSamw 		if ('0' <= c && c <= '9') {
540da6c28aaSamw 			repc = 0;
541da6c28aaSamw 			do {
542da6c28aaSamw 				repc = repc * 10 + c - '0';
543da6c28aaSamw 				c = *fmt++;
544da6c28aaSamw 			} while ('0' <= c && c <= '9');
54512b65585SGordon Ross 			repc_specified = B_TRUE;
546da6c28aaSamw 		} else if (c == '#') {
547da6c28aaSamw 			repc = va_arg(ap, int);
548da6c28aaSamw 			c = *fmt++;
54912b65585SGordon Ross 			repc_specified = B_TRUE;
550da6c28aaSamw 		}
551da6c28aaSamw 
552da6c28aaSamw 		switch (c) {
553da6c28aaSamw 		case '%':
554da6c28aaSamw 			sr = va_arg(ap, struct smb_request *);
555a90cf9f2SGordon Ross 			if (sr->session->dialect >= SMB_VERS_2_BASE) {
556a90cf9f2SGordon Ross 				unicode = 1;
557a90cf9f2SGordon Ross 				break;
558a90cf9f2SGordon Ross 			}
559da6c28aaSamw 			unicode = sr->smb_flg2 & SMB_FLAGS2_UNICODE;
560da6c28aaSamw 			break;
561da6c28aaSamw 
562da6c28aaSamw 		case 'C':	/* Mbuf_chain */
563da6c28aaSamw 			if (mbc_marshal_put_mbuf_chain(mbc,
5643db3f65cSamw 			    va_arg(ap, mbuf_chain_t *)) != 0)
565da6c28aaSamw 				return (DECODE_NO_MORE_DATA);
566da6c28aaSamw 			break;
567da6c28aaSamw 
568da6c28aaSamw 		case 'D':
569da6c28aaSamw 			vdp = va_arg(ap, struct vardata_block *);
570da6c28aaSamw 
571da6c28aaSamw 			if (mbc_marshal_put_char(mbc, 1) != 0)
572da6c28aaSamw 				return (DECODE_NO_MORE_DATA);
5732c2961f8Sjose borrego 			if (mbc_marshal_put_short(mbc, vdp->vdb_len) != 0)
574da6c28aaSamw 				return (DECODE_NO_MORE_DATA);
5752c2961f8Sjose borrego 			if (mbc_marshal_put_uio(mbc, &vdp->vdb_uio) != 0)
576da6c28aaSamw 				return (DECODE_NO_MORE_DATA);
577da6c28aaSamw 			break;
578da6c28aaSamw 
579da6c28aaSamw 		case 'M':
580da6c28aaSamw 			/* 0xFF S M B */
581da6c28aaSamw 			if (mbc_marshal_put_long(mbc, 0x424D53FF))
582da6c28aaSamw 				return (DECODE_NO_MORE_DATA);
583da6c28aaSamw 			break;
584da6c28aaSamw 
585a90cf9f2SGordon Ross 		case 'N':
586a90cf9f2SGordon Ross 			/* 0xFE S M B */
587a90cf9f2SGordon Ross 			if (mbc_marshal_put_long(mbc, 0x424D53FE))
588a90cf9f2SGordon Ross 				return (DECODE_NO_MORE_DATA);
589a90cf9f2SGordon Ross 			break;
590a90cf9f2SGordon Ross 
591da6c28aaSamw 		case 'T':
592da6c28aaSamw 			tvp = va_arg(ap, timestruc_t *);
593e3f2c991SKeyur Desai 			nt_time = smb_time_unix_to_nt(tvp);
594da6c28aaSamw 			if (mbc_marshal_put_long_long(mbc, nt_time) != 0)
595da6c28aaSamw 				return (DECODE_NO_MORE_DATA);
596da6c28aaSamw 			break;
597da6c28aaSamw 
598da6c28aaSamw 		case 'V':
599da6c28aaSamw 			vdp = va_arg(ap, struct vardata_block *);
600da6c28aaSamw 
601da6c28aaSamw 			if (mbc_marshal_put_char(mbc, 5) != 0)
602da6c28aaSamw 				return (DECODE_NO_MORE_DATA);
6032c2961f8Sjose borrego 			if (mbc_marshal_put_short(mbc, vdp->vdb_len) != 0)
604da6c28aaSamw 				return (DECODE_NO_MORE_DATA);
6052c2961f8Sjose borrego 			if (mbc_marshal_put_uio(mbc, &vdp->vdb_uio) != 0)
606da6c28aaSamw 				return (DECODE_NO_MORE_DATA);
607da6c28aaSamw 			break;
608da6c28aaSamw 
609da6c28aaSamw 		case 'b':
610da6c28aaSamw 			while (repc-- > 0) {
611da6c28aaSamw 				cval = va_arg(ap, int);
612da6c28aaSamw 				if (mbc_marshal_put_char(mbc, cval) != 0)
613da6c28aaSamw 					return (DECODE_NO_MORE_DATA);
614da6c28aaSamw 			}
615da6c28aaSamw 			break;
616da6c28aaSamw 
617da6c28aaSamw 		case 'm':	/* struct_mbuf */
618da6c28aaSamw 			if (mbc_marshal_put_mbufs(mbc,
6193db3f65cSamw 			    va_arg(ap, mbuf_t *)) != 0)
620da6c28aaSamw 				return (DECODE_NO_MORE_DATA);
621da6c28aaSamw 			break;
622da6c28aaSamw 
623da6c28aaSamw 		case 'c':
6243db3f65cSamw 			cvalp = va_arg(ap, uint8_t *);
625da6c28aaSamw 			while (repc-- > 0) {
626da6c28aaSamw 				if (mbc_marshal_put_char(mbc,
627da6c28aaSamw 				    *cvalp++) != 0)
628da6c28aaSamw 					return (DECODE_NO_MORE_DATA);
629da6c28aaSamw 			}
630da6c28aaSamw 			break;
631da6c28aaSamw 
632da6c28aaSamw 		case 'w':
633da6c28aaSamw 			while (repc-- > 0) {
634da6c28aaSamw 				wval = va_arg(ap, int);
635da6c28aaSamw 				if (mbc_marshal_put_short(mbc, wval) != 0)
636da6c28aaSamw 					return (DECODE_NO_MORE_DATA);
637da6c28aaSamw 			}
638da6c28aaSamw 			break;
639da6c28aaSamw 
640da6c28aaSamw 		case 'l':
641da6c28aaSamw 			while (repc-- > 0) {
642da6c28aaSamw 				lval = va_arg(ap, uint32_t);
643da6c28aaSamw 				if (mbc_marshal_put_long(mbc, lval) != 0)
644da6c28aaSamw 					return (DECODE_NO_MORE_DATA);
645da6c28aaSamw 			}
646da6c28aaSamw 			break;
647da6c28aaSamw 
648da6c28aaSamw 		case 'q':
649da6c28aaSamw 			while (repc-- > 0) {
650da6c28aaSamw 				llval = va_arg(ap, uint64_t);
651da6c28aaSamw 				if (mbc_marshal_put_long_long(mbc, llval) != 0)
652da6c28aaSamw 					return (DECODE_NO_MORE_DATA);
653da6c28aaSamw 			}
654da6c28aaSamw 			break;
655da6c28aaSamw 
656da6c28aaSamw 
657da6c28aaSamw 		case 'L':
658da6c28aaSamw 			tag = 2;
65907a6ae61SGordon Ross 			goto oem_conversion;
660da6c28aaSamw 
661da6c28aaSamw 		case 'S':
6623db3f65cSamw 		case 'A':
6633db3f65cSamw 			tag = 4;
6643db3f65cSamw 			goto tagged_str;
6653db3f65cSamw 
6663db3f65cSamw 		case 'P':
6673db3f65cSamw 			tag = 3;
6683db3f65cSamw 			goto tagged_str;
6693db3f65cSamw 
670da6c28aaSamw 		tagged_str:
671da6c28aaSamw 			if (mbc_marshal_put_char(mbc, tag) != 0)
672da6c28aaSamw 				return (DECODE_NO_MORE_DATA);
673da6c28aaSamw 			/* FALLTHROUGH */
674da6c28aaSamw 
675da6c28aaSamw 		case 'u':	/* Convert from unicode if flags are set */
676da6c28aaSamw 			if (unicode)
677da6c28aaSamw 				goto unicode_translation;
678da6c28aaSamw 			/* FALLTHROUGH */
679da6c28aaSamw 
6807d1ffc32SGordon Ross 		case 's':	/* put OEM string */
68107a6ae61SGordon Ross oem_conversion:
68207a6ae61SGordon Ross 			charp = va_arg(ap, char *);
68312b65585SGordon Ross 			if (!repc_specified)
68412b65585SGordon Ross 				repc = 0;
6857d1ffc32SGordon Ross 			if (mbc_marshal_put_oem_string(mbc,
68607a6ae61SGordon Ross 			    charp, repc) != 0)
68707a6ae61SGordon Ross 				return (DECODE_NO_MORE_DATA);
68807a6ae61SGordon Ross 			break;
68907a6ae61SGordon Ross 
6907d1ffc32SGordon Ross 		case 'U':	/* put UTF-16 string */
69107a6ae61SGordon Ross unicode_translation:
69207a6ae61SGordon Ross 			charp = va_arg(ap, char *);
69307a6ae61SGordon Ross 			if (!repc_specified)
69407a6ae61SGordon Ross 				repc = 0;
69507a6ae61SGordon Ross 			if (mbc_marshal_put_unicode_string(mbc,
69607a6ae61SGordon Ross 			    charp, repc) != 0)
697da6c28aaSamw 				return (DECODE_NO_MORE_DATA);
698da6c28aaSamw 			break;
699da6c28aaSamw 
700da6c28aaSamw 		case 'Y':		/* int32_t, encode dos date/time */
701da6c28aaSamw 			while (repc-- > 0) {
7023db3f65cSamw 				uint16_t	d, t;
703da6c28aaSamw 
704da6c28aaSamw 				lval = va_arg(ap, uint32_t);
705e3f2c991SKeyur Desai 				smb_time_unix_to_dos(lval,
706da6c28aaSamw 				    (short *)&d, (short *)&t);
707da6c28aaSamw 				if (mbc_marshal_put_short(mbc, t) != 0)
708da6c28aaSamw 					return (DECODE_NO_MORE_DATA);
709da6c28aaSamw 				if (mbc_marshal_put_short(mbc, d) != 0)
710da6c28aaSamw 					return (DECODE_NO_MORE_DATA);
711da6c28aaSamw 			}
712da6c28aaSamw 			break;
713da6c28aaSamw 
714da6c28aaSamw 		case 'y':		/* int32_t, encode dos date/time */
715da6c28aaSamw 			while (repc-- > 0) {
7163db3f65cSamw 				uint16_t	d, t;
717da6c28aaSamw 
718da6c28aaSamw 				lval = va_arg(ap, uint32_t);
719e3f2c991SKeyur Desai 				smb_time_unix_to_dos(lval,
720da6c28aaSamw 				    (short *)&d, (short *)&t);
721da6c28aaSamw 				if (mbc_marshal_put_short(mbc, d) != 0)
722da6c28aaSamw 					return (DECODE_NO_MORE_DATA);
723da6c28aaSamw 				if (mbc_marshal_put_short(mbc, t) != 0)
724da6c28aaSamw 					return (DECODE_NO_MORE_DATA);
725da6c28aaSamw 			}
726da6c28aaSamw 			break;
727da6c28aaSamw 
728da6c28aaSamw 		case ',':
729da6c28aaSamw 			if (unicode)
730da6c28aaSamw 				repc *= 2;
731da6c28aaSamw 			/* FALLTHROUGH */
732da6c28aaSamw 
733da6c28aaSamw 		case '.':
734da6c28aaSamw 			while (repc-- > 0)
735da6c28aaSamw 				if (mbc_marshal_put_char(mbc, 0) != 0)
736da6c28aaSamw 					return (DECODE_NO_MORE_DATA);
737da6c28aaSamw 			break;
738da6c28aaSamw 
7393db3f65cSamw 		default:
7403db3f65cSamw 			ASSERT(0);
7413db3f65cSamw 			return (-1);
742da6c28aaSamw 		}
743da6c28aaSamw 	}
744da6c28aaSamw 	return (0);
745da6c28aaSamw }
746da6c28aaSamw 
7473db3f65cSamw /*
7483db3f65cSamw  * smb_mbc_encodef
7493db3f65cSamw  *
7503db3f65cSamw  * This function builds a stream of bytes in the mbc chain passed in under the
7513db3f65cSamw  * control of the format fmt.
7523db3f65cSamw  *
7533db3f65cSamw  * (for a description of the format string see smb_mbc_vencodef()).
7543db3f65cSamw  */
755da6c28aaSamw int
smb_mbc_encodef(mbuf_chain_t * mbc,const char * fmt,...)756a90cf9f2SGordon Ross smb_mbc_encodef(mbuf_chain_t *mbc, const char *fmt, ...)
757da6c28aaSamw {
758da6c28aaSamw 	int	rc;
759da6c28aaSamw 	va_list	ap;
760da6c28aaSamw 
761da6c28aaSamw 	va_start(ap, fmt);
7623db3f65cSamw 	rc = smb_mbc_vencodef(mbc, fmt, ap);
763da6c28aaSamw 	va_end(ap);
764da6c28aaSamw 	return (rc);
765da6c28aaSamw }
766da6c28aaSamw 
7673db3f65cSamw /*
7683db3f65cSamw  * smb_mbc_poke
7693db3f65cSamw  *
7703db3f65cSamw  * This function writes a stream of bytes in the mbc passed in at the specified
7713db3f65cSamw  * offset under the control of the format fmt. The offset of the chain passed in
7723db3f65cSamw  * is not modified.
7733db3f65cSamw  *
7743db3f65cSamw  * (for a description of the format string see smb_mbc_vencodef()).
7753db3f65cSamw  */
776da6c28aaSamw int
smb_mbc_poke(mbuf_chain_t * mbc,int offset,const char * fmt,...)777a90cf9f2SGordon Ross smb_mbc_poke(mbuf_chain_t *mbc, int offset, const char *fmt, ...)
778da6c28aaSamw {
779a90cf9f2SGordon Ross 	int		len, rc;
7803db3f65cSamw 	mbuf_chain_t	tmp;
781da6c28aaSamw 	va_list		ap;
782da6c28aaSamw 
783a90cf9f2SGordon Ross 	if ((len = mbc->max_bytes - offset) < 0)
784a90cf9f2SGordon Ross 		return (DECODE_NO_MORE_DATA);
785a90cf9f2SGordon Ross 	rc = MBC_SHADOW_CHAIN(&tmp, mbc, offset, len);
786a90cf9f2SGordon Ross 	if (rc)
787a90cf9f2SGordon Ross 		return (DECODE_NO_MORE_DATA);
788a90cf9f2SGordon Ross 
789da6c28aaSamw 	va_start(ap, fmt);
790a90cf9f2SGordon Ross 	rc = smb_mbc_vencodef(&tmp, fmt, ap);
791da6c28aaSamw 	va_end(ap);
792a90cf9f2SGordon Ross 
793a90cf9f2SGordon Ross 	return (rc);
794da6c28aaSamw }
7953db3f65cSamw 
7963db3f65cSamw /*
7977f3ef643SGordon Ross  * Copy data from the src mbuf chain to the dst mbuf chain,
7987f3ef643SGordon Ross  * at the given offset in the src and current offset in dst,
7997f3ef643SGordon Ross  * for copy_len bytes.  Does NOT update src->chain_offset.
8007f3ef643SGordon Ross  */
8017f3ef643SGordon Ross int
smb_mbc_copy(mbuf_chain_t * dst_mbc,const mbuf_chain_t * src_mbc,int copy_offset,int copy_len)8027f3ef643SGordon Ross smb_mbc_copy(mbuf_chain_t *dst_mbc, const mbuf_chain_t *src_mbc,
8037f3ef643SGordon Ross     int copy_offset, int copy_len)
8047f3ef643SGordon Ross {
8057f3ef643SGordon Ross 	mbuf_t	*src_m;
8067f3ef643SGordon Ross 	int offset, len;
8077f3ef643SGordon Ross 	int rc;
8087f3ef643SGordon Ross 
8097f3ef643SGordon Ross 	if (copy_len <= 0)
8107f3ef643SGordon Ross 		return (0);
8117f3ef643SGordon Ross 	if (copy_offset < 0)
8127f3ef643SGordon Ross 		return (EINVAL);
8137f3ef643SGordon Ross 	if ((copy_offset + copy_len) > src_mbc->max_bytes)
8147f3ef643SGordon Ross 		return (EMSGSIZE);
8157f3ef643SGordon Ross 
8167f3ef643SGordon Ross 	/*
8177f3ef643SGordon Ross 	 * Advance to the src mbuf where we start copying.
8187f3ef643SGordon Ross 	 */
8197f3ef643SGordon Ross 	offset = copy_offset;
8207f3ef643SGordon Ross 	src_m = src_mbc->chain;
8217f3ef643SGordon Ross 	while (src_m && offset >= src_m->m_len) {
8227f3ef643SGordon Ross 		offset -= src_m->m_len;
8237f3ef643SGordon Ross 		src_m = src_m->m_next;
8247f3ef643SGordon Ross 	}
8257f3ef643SGordon Ross 	if (src_m == NULL)
8267f3ef643SGordon Ross 		return (EFAULT);
8277f3ef643SGordon Ross 
8287f3ef643SGordon Ross 	/*
8297f3ef643SGordon Ross 	 * Copy the first part, which may start somewhere past
8307f3ef643SGordon Ross 	 * the beginning of the current mbuf.
8317f3ef643SGordon Ross 	 */
8327f3ef643SGordon Ross 	len = src_m->m_len - offset;
8337f3ef643SGordon Ross 	if (len > copy_len)
8347f3ef643SGordon Ross 		len = copy_len;
8357f3ef643SGordon Ross 	rc = smb_mbc_put_mem(dst_mbc, src_m->m_data + offset, len);
8367f3ef643SGordon Ross 	if (rc != 0)
8377f3ef643SGordon Ross 		return (rc);
8387f3ef643SGordon Ross 	copy_len -= len;
8397f3ef643SGordon Ross 
8407f3ef643SGordon Ross 	/*
8417f3ef643SGordon Ross 	 * Copy remaining mbufs...
8427f3ef643SGordon Ross 	 */
8437f3ef643SGordon Ross 	while (copy_len > 0) {
8447f3ef643SGordon Ross 		src_m = src_m->m_next;
8457f3ef643SGordon Ross 		if (src_m == NULL)
8467f3ef643SGordon Ross 			break;
8477f3ef643SGordon Ross 		len = src_m->m_len;
8487f3ef643SGordon Ross 		if (len > copy_len)
8497f3ef643SGordon Ross 			len = copy_len;
8507f3ef643SGordon Ross 		rc = smb_mbc_put_mem(dst_mbc, src_m->m_data, len);
8517f3ef643SGordon Ross 		copy_len -= len;
8527f3ef643SGordon Ross 	}
8537f3ef643SGordon Ross 
8547f3ef643SGordon Ross 	return (0);
8557f3ef643SGordon Ross }
8567f3ef643SGordon Ross 
8577f3ef643SGordon Ross /*
8587f3ef643SGordon Ross  * Copy data from the passed memory buffer into the mbuf chain
8597f3ef643SGordon Ross  * at the current offset.
8607f3ef643SGordon Ross  */
8617f3ef643SGordon Ross int
smb_mbc_put_mem(mbuf_chain_t * mbc,void * vmem,int mem_len)8627f3ef643SGordon Ross smb_mbc_put_mem(mbuf_chain_t *mbc, void *vmem, int mem_len)
8637f3ef643SGordon Ross {
8647f3ef643SGordon Ross 	caddr_t mem = vmem;
8657f3ef643SGordon Ross 	mbuf_t	*m;
8667f3ef643SGordon Ross 	int32_t	offset, tlen;
8677f3ef643SGordon Ross 	int rc;
8687f3ef643SGordon Ross 
8697f3ef643SGordon Ross 	if (mem_len <= 0)
8707f3ef643SGordon Ross 		return (0);
8717f3ef643SGordon Ross 
8727f3ef643SGordon Ross 	if ((rc = mbc_marshal_make_room(mbc, mem_len)) != 0)
8737f3ef643SGordon Ross 		return (rc);
8747f3ef643SGordon Ross 
8757f3ef643SGordon Ross 	/*
8767f3ef643SGordon Ross 	 * Advance to the dst mbuf where we start copying.
8777f3ef643SGordon Ross 	 * Allocations were done by _make_room().
8787f3ef643SGordon Ross 	 */
8797f3ef643SGordon Ross 	offset = mbc->chain_offset;
8807f3ef643SGordon Ross 	m = mbc->chain;
8817f3ef643SGordon Ross 	while (offset >= m->m_len) {
8827f3ef643SGordon Ross 		ASSERT(m->m_len > 0);
8837f3ef643SGordon Ross 		offset -= m->m_len;
8847f3ef643SGordon Ross 		m = m->m_next;
8857f3ef643SGordon Ross 	}
8867f3ef643SGordon Ross 
8877f3ef643SGordon Ross 	/*
8887f3ef643SGordon Ross 	 * Copy the first part, which may start somewhere past
8897f3ef643SGordon Ross 	 * the beginning of the current mbuf.
8907f3ef643SGordon Ross 	 */
8917f3ef643SGordon Ross 	tlen = m->m_len - offset;
8927f3ef643SGordon Ross 	if (tlen > mem_len)
8937f3ef643SGordon Ross 		tlen = mem_len;
8947f3ef643SGordon Ross 	bcopy(mem, m->m_data + offset, tlen);
8957f3ef643SGordon Ross 	mbc->chain_offset += tlen;
8967f3ef643SGordon Ross 	mem += tlen;
8977f3ef643SGordon Ross 	mem_len -= tlen;
8987f3ef643SGordon Ross 
8997f3ef643SGordon Ross 	/*
9007f3ef643SGordon Ross 	 * Copy remaining mem into mbufs.  These all start
9017f3ef643SGordon Ross 	 * at the beginning of each mbuf, and the last may
9027f3ef643SGordon Ross 	 * end somewhere short of m_len.
9037f3ef643SGordon Ross 	 */
9047f3ef643SGordon Ross 	while (mem_len > 0) {
9057f3ef643SGordon Ross 		m = m->m_next;
9067f3ef643SGordon Ross 		tlen = m->m_len;
9077f3ef643SGordon Ross 		if (tlen > mem_len)
9087f3ef643SGordon Ross 			tlen = mem_len;
9097f3ef643SGordon Ross 		bcopy(mem, m->m_data, tlen);
9107f3ef643SGordon Ross 		mbc->chain_offset += tlen;
9117f3ef643SGordon Ross 		mem += tlen;
9127f3ef643SGordon Ross 		mem_len -= tlen;
9137f3ef643SGordon Ross 	}
9147f3ef643SGordon Ross 
9157f3ef643SGordon Ross 	return (0);
9167f3ef643SGordon Ross }
9177f3ef643SGordon Ross 
9187f3ef643SGordon Ross /*
919d2488fe8SGordon Ross  * Put padding sufficient to align to A, where
920d2488fe8SGordon Ross  * A is some power of 2 greater than zero.
921d2488fe8SGordon Ross  */
922d2488fe8SGordon Ross int
smb_mbc_put_align(mbuf_chain_t * mbc,int align)923d2488fe8SGordon Ross smb_mbc_put_align(mbuf_chain_t *mbc, int align)
924d2488fe8SGordon Ross {
925d2488fe8SGordon Ross 	int mask = align - 1;
926d2488fe8SGordon Ross 	int padsz;
927d2488fe8SGordon Ross 
928d2488fe8SGordon Ross 	ASSERT(align > 0 && (align & mask) == 0);
929d2488fe8SGordon Ross 	if ((mbc->chain_offset & mask) == 0)
930d2488fe8SGordon Ross 		return (0);
931d2488fe8SGordon Ross 	padsz = align - (mbc->chain_offset & mask);
932d2488fe8SGordon Ross 	return (smb_mbc_encodef(mbc, "#.", padsz));
933d2488fe8SGordon Ross }
934d2488fe8SGordon Ross 
935d2488fe8SGordon Ross /*
9363db3f65cSamw  * Put data into mbuf chain allocating as needed.
9373db3f65cSamw  * Adds room to end of mbuf chain if needed.
9383db3f65cSamw  */
9393db3f65cSamw static int
mbc_marshal_make_room(mbuf_chain_t * mbc,int32_t bytes_needed)9403db3f65cSamw mbc_marshal_make_room(mbuf_chain_t *mbc, int32_t bytes_needed)
9413db3f65cSamw {
9423db3f65cSamw 	mbuf_t	*m;
943*897907ceSGordon Ross 	mbuf_t	*last;
9443db3f65cSamw 	int32_t	bytes_available;
9453db3f65cSamw 
9463db3f65cSamw 	bytes_needed += mbc->chain_offset;
9473db3f65cSamw 	if (bytes_needed > mbc->max_bytes)
9483db3f65cSamw 		return (EMSGSIZE);
9493db3f65cSamw 
950*897907ceSGordon Ross 	/*
951*897907ceSGordon Ross 	 * First mbuf in chain should have prepend space.
952*897907ceSGordon Ross 	 * See M_LEADINGSPACE() below.
953*897907ceSGordon Ross 	 */
954*897907ceSGordon Ross 	if ((m = mbc->chain) == NULL) {
9553db3f65cSamw 		MGET(m, M_WAIT, MT_DATA);
9563db3f65cSamw 		m->m_len = 0;
9573db3f65cSamw 		MCLGET(m, M_WAIT);
958*897907ceSGordon Ross 		m->m_data += MH_PREPEND_SPACE;
9593db3f65cSamw 		mbc->chain = m;
9603db3f65cSamw 		/* xxxx */
9613db3f65cSamw 		/* ^    */
9623db3f65cSamw 	}
9633db3f65cSamw 
9643db3f65cSamw 	/* ---- ----- --xx ---xxx */
9653db3f65cSamw 	/* ^			  */
9663db3f65cSamw 
967*897907ceSGordon Ross 	last = NULL;
968*897907ceSGordon Ross 	while ((m != NULL) && (bytes_needed >= m->m_len)) {
969*897907ceSGordon Ross 		last = m;
9703db3f65cSamw 		bytes_needed -= m->m_len;
9713db3f65cSamw 		m = m->m_next;
9723db3f65cSamw 	}
9733db3f65cSamw 
974*897907ceSGordon Ross 	if ((bytes_needed == 0) || (m != NULL)) {
9753db3f65cSamw 		/* We have enough room already */
9763db3f65cSamw 		return (0);
9773db3f65cSamw 	}
9783db3f65cSamw 
9793db3f65cSamw 	/* ---- ----- --xx ---xxx */
9803db3f65cSamw 	/*			 ^ */
9813db3f65cSamw 	/* Back up to start of last mbuf */
982*897907ceSGordon Ross 	m = last;
9833db3f65cSamw 	bytes_needed += m->m_len;
9843db3f65cSamw 
9853db3f65cSamw 	/* ---- ----- --xx ---xxx */
9863db3f65cSamw 	/*		   ^	  */
987*897907ceSGordon Ross 	bytes_available = M_SIZE(m) - M_LEADINGSPACE(m);
9883db3f65cSamw 
9893db3f65cSamw 	/* ---- ----- --xx ---xxx */
9903db3f65cSamw 	/*		   ^	  */
9913db3f65cSamw 	while ((bytes_needed != 0) && (bytes_needed > bytes_available)) {
9923db3f65cSamw 		m->m_len = bytes_available;
9933db3f65cSamw 		bytes_needed -= m->m_len;
9943db3f65cSamw 		/* ---- ----- --xx ------ */
9953db3f65cSamw 		/*		   ^	  */
9963db3f65cSamw 
9973db3f65cSamw 		MGET(m->m_next, M_WAIT, MT_DATA);
9983db3f65cSamw 		m = m->m_next;
9993db3f65cSamw 		m->m_len = 0;
10003db3f65cSamw 		MCLGET(m, M_WAIT);
10013db3f65cSamw 
1002*897907ceSGordon Ross 		ASSERT(M_LEADINGSPACE(m) == 0);
1003*897907ceSGordon Ross 		bytes_available = M_SIZE(m);
10043db3f65cSamw 
10053db3f65cSamw 		/* ---- ----- --xx ------ xxxx */
10063db3f65cSamw 		/*			  ^    */
10073db3f65cSamw 	}
10083db3f65cSamw 
10093db3f65cSamw 	/* ---- ----- --xx ------ xxxx */
10103db3f65cSamw 	/*			  ^    */
10113db3f65cSamw 	/* Expand last tail as needed */
10123db3f65cSamw 	if (m->m_len <= bytes_needed) {
10133db3f65cSamw 		m->m_len = bytes_needed;
10143db3f65cSamw 		/* ---- ----- --xx ------ --xx */
10153db3f65cSamw 		/*			   ^   */
10163db3f65cSamw 	}
10173db3f65cSamw 
10183db3f65cSamw 	return (0);
10193db3f65cSamw }
10203db3f65cSamw 
10213db3f65cSamw static void
mbc_marshal_store_byte(mbuf_chain_t * mbc,uint8_t data)10223db3f65cSamw mbc_marshal_store_byte(mbuf_chain_t *mbc, uint8_t data)
10233db3f65cSamw {
10243db3f65cSamw 	mbuf_t	*m = mbc->chain;
10253db3f65cSamw 	int32_t	cur_offset = mbc->chain_offset;
10263db3f65cSamw 
10273db3f65cSamw 	/*
10283db3f65cSamw 	 * Scan forward looking for the last data currently in chain.
10293db3f65cSamw 	 */
10303db3f65cSamw 	while (cur_offset >= m->m_len) {
10313db3f65cSamw 		cur_offset -= m->m_len;
10323db3f65cSamw 		m = m->m_next;
10333db3f65cSamw 	}
10343db3f65cSamw 	((char *)m->m_data)[cur_offset] = data;
10353db3f65cSamw 	mbc->chain_offset++;
10363db3f65cSamw }
10373db3f65cSamw 
10383db3f65cSamw static int
mbc_marshal_put_char(mbuf_chain_t * mbc,uint8_t data)10393db3f65cSamw mbc_marshal_put_char(mbuf_chain_t *mbc, uint8_t data)
10403db3f65cSamw {
10413db3f65cSamw 	if (mbc_marshal_make_room(mbc, sizeof (char)) != 0)
10423db3f65cSamw 		return (DECODE_NO_MORE_DATA);
10433db3f65cSamw 	mbc_marshal_store_byte(mbc, data);
10443db3f65cSamw 	return (0);
10453db3f65cSamw }
10463db3f65cSamw 
10473db3f65cSamw static int
mbc_marshal_put_short(mbuf_chain_t * mbc,uint16_t data)10483db3f65cSamw mbc_marshal_put_short(mbuf_chain_t *mbc, uint16_t data)
10493db3f65cSamw {
10503db3f65cSamw 	if (mbc_marshal_make_room(mbc, sizeof (short)))
10513db3f65cSamw 		return (DECODE_NO_MORE_DATA);
10523db3f65cSamw 	mbc_marshal_store_byte(mbc, data);
10533db3f65cSamw 	mbc_marshal_store_byte(mbc, data >> 8);
10543db3f65cSamw 	return (0);
10553db3f65cSamw }
10563db3f65cSamw 
10573db3f65cSamw static int
mbc_marshal_put_long(mbuf_chain_t * mbc,uint32_t data)10583db3f65cSamw mbc_marshal_put_long(mbuf_chain_t *mbc, uint32_t data)
10593db3f65cSamw {
10603db3f65cSamw 	if (mbc_marshal_make_room(mbc, sizeof (int32_t)))
10613db3f65cSamw 		return (DECODE_NO_MORE_DATA);
10623db3f65cSamw 	mbc_marshal_store_byte(mbc, data);
10633db3f65cSamw 	mbc_marshal_store_byte(mbc, data >> 8);
10643db3f65cSamw 	mbc_marshal_store_byte(mbc, data >> 16);
10653db3f65cSamw 	mbc_marshal_store_byte(mbc, data >> 24);
10663db3f65cSamw 	return (0);
10673db3f65cSamw }
10683db3f65cSamw 
10693db3f65cSamw static int
mbc_marshal_put_long_long(mbuf_chain_t * mbc,uint64_t data)10703db3f65cSamw mbc_marshal_put_long_long(mbuf_chain_t *mbc, uint64_t data)
10713db3f65cSamw {
10723db3f65cSamw 	if (mbc_marshal_make_room(mbc, sizeof (int64_t)))
10733db3f65cSamw 		return (DECODE_NO_MORE_DATA);
10743db3f65cSamw 
10753db3f65cSamw 	mbc_marshal_store_byte(mbc, data);
10763db3f65cSamw 	mbc_marshal_store_byte(mbc, data >> 8);
10773db3f65cSamw 	mbc_marshal_store_byte(mbc, data >> 16);
10783db3f65cSamw 	mbc_marshal_store_byte(mbc, data >> 24);
10793db3f65cSamw 	mbc_marshal_store_byte(mbc, data >> 32);
10803db3f65cSamw 	mbc_marshal_store_byte(mbc, data >> 40);
10813db3f65cSamw 	mbc_marshal_store_byte(mbc, data >> 48);
10823db3f65cSamw 	mbc_marshal_store_byte(mbc, data >> 56);
10833db3f65cSamw 	return (0);
10843db3f65cSamw }
10853db3f65cSamw 
10863db3f65cSamw /*
108707a6ae61SGordon Ross  * Marshal a UTF-8 string (str) into mbc, converting to OEM codeset.
108807a6ae61SGordon Ross  * Also write a null unless the repc count limits the length we put.
10897d1ffc32SGordon Ross  * When (repc > 0) the length we marshal must be exactly repc, and
10907d1ffc32SGordon Ross  * truncate or pad the mbc data as necessary.
10917d1ffc32SGordon Ross  * See also: msgbuf_put_oem_string
10923db3f65cSamw  */
10933db3f65cSamw static int
mbc_marshal_put_oem_string(mbuf_chain_t * mbc,char * mbs,int repc)10947d1ffc32SGordon Ross mbc_marshal_put_oem_string(mbuf_chain_t *mbc, char *mbs, int repc)
10953db3f65cSamw {
10967d1ffc32SGordon Ross 	uint8_t		*oembuf = NULL;
10977d1ffc32SGordon Ross 	uint8_t		*s;
109807a6ae61SGordon Ross 	int		oemlen;
10997d1ffc32SGordon Ross 	int		rlen;
11007d1ffc32SGordon Ross 	int		rc;
11013db3f65cSamw 
11023db3f65cSamw 	/*
11037d1ffc32SGordon Ross 	 * Compute length of converted OEM string,
11047d1ffc32SGordon Ross 	 * NOT including null terminator
11053db3f65cSamw 	 */
11067d1ffc32SGordon Ross 	if ((oemlen = smb_sbequiv_strlen(mbs)) == -1)
11073db3f65cSamw 		return (DECODE_NO_MORE_DATA);
11083db3f65cSamw 
11097d1ffc32SGordon Ross 	/*
11107d1ffc32SGordon Ross 	 * If repc not specified, put whole string + NULL,
11117d1ffc32SGordon Ross 	 * otherwise will truncate or pad as needed.
11127d1ffc32SGordon Ross 	 */
11137d1ffc32SGordon Ross 	if (repc <= 0)
11147d1ffc32SGordon Ross 		repc = oemlen + 1;
111507a6ae61SGordon Ross 
11167d1ffc32SGordon Ross 	/*
11177d1ffc32SGordon Ross 	 * Convert into a temporary buffer
11187d1ffc32SGordon Ross 	 * Free oembuf before return.
11197d1ffc32SGordon Ross 	 */
11207d1ffc32SGordon Ross 	oembuf = smb_mem_zalloc(oemlen + 1);
11217d1ffc32SGordon Ross 	ASSERT(oembuf != NULL);
11227d1ffc32SGordon Ross 	rlen = smb_mbstooem(oembuf, mbs, oemlen);
11237d1ffc32SGordon Ross 	if (rlen < 0) {
11247d1ffc32SGordon Ross 		rc = DECODE_NO_MORE_DATA;
11257d1ffc32SGordon Ross 		goto out;
11263db3f65cSamw 	}
11277d1ffc32SGordon Ross 	if (rlen > oemlen)
11287d1ffc32SGordon Ross 		rlen = oemlen;
11297d1ffc32SGordon Ross 	oembuf[rlen] = '\0';
11303db3f65cSamw 
11317d1ffc32SGordon Ross 	/*
11327d1ffc32SGordon Ross 	 * Copy the converted string into the message,
11337d1ffc32SGordon Ross 	 * truncated or paded as required.
11347d1ffc32SGordon Ross 	 */
11357d1ffc32SGordon Ross 	s = oembuf;
11367d1ffc32SGordon Ross 	while (repc > 0) {
113725a9a7aaSGordon Ross 		if (mbc_marshal_make_room(mbc, 1)) {
113825a9a7aaSGordon Ross 			rc = DECODE_NO_MORE_DATA;
113925a9a7aaSGordon Ross 			goto out;
114025a9a7aaSGordon Ross 		}
11417d1ffc32SGordon Ross 		mbc_marshal_store_byte(mbc, *s);
11427d1ffc32SGordon Ross 		if (*s != '\0')
11437d1ffc32SGordon Ross 			s++;
11447d1ffc32SGordon Ross 		repc--;
11457d1ffc32SGordon Ross 	}
11467d1ffc32SGordon Ross 	rc = 0;
11477d1ffc32SGordon Ross 
11487d1ffc32SGordon Ross out:
11497d1ffc32SGordon Ross 	if (oembuf != NULL)
11507d1ffc32SGordon Ross 		smb_mem_free(oembuf);
11517d1ffc32SGordon Ross 	return (rc);
11523db3f65cSamw }
11533db3f65cSamw 
115407a6ae61SGordon Ross /*
115507a6ae61SGordon Ross  * Marshal a UTF-8 string (str) into mbc, converting to UTF-16.
11567d1ffc32SGordon Ross  * Also write a null unless the repc count limits the length.
11577d1ffc32SGordon Ross  * When (repc > 0) the length we marshal must be exactly repc,
11587d1ffc32SGordon Ross  * and truncate or pad the mbc data as necessary.
11597d1ffc32SGordon Ross  * See also: msgbuf_put_unicode_string
116007a6ae61SGordon Ross  */
11613db3f65cSamw static int
mbc_marshal_put_unicode_string(mbuf_chain_t * mbc,char * mbs,int repc)11627d1ffc32SGordon Ross mbc_marshal_put_unicode_string(mbuf_chain_t *mbc, char *mbs, int repc)
11633db3f65cSamw {
11647d1ffc32SGordon Ross 	smb_wchar_t	*wcsbuf = NULL;
11657d1ffc32SGordon Ross 	smb_wchar_t	*wp;
116625a9a7aaSGordon Ross 	smb_wchar_t	wchar;
11677d1ffc32SGordon Ross 	size_t		wcslen, wcsbytes;
11687d1ffc32SGordon Ross 	size_t		rlen;
11697d1ffc32SGordon Ross 	int		rc;
11703db3f65cSamw 
11717d1ffc32SGordon Ross 	/* align to word boundary */
11727d1ffc32SGordon Ross 	if (mbc->chain_offset & 1) {
11737d1ffc32SGordon Ross 		if (mbc_marshal_make_room(mbc, 1))
11743db3f65cSamw 			return (DECODE_NO_MORE_DATA);
11757d1ffc32SGordon Ross 		mbc_marshal_store_byte(mbc, 0);
11767d1ffc32SGordon Ross 	}
11773db3f65cSamw 
11783db3f65cSamw 	/*
11797d1ffc32SGordon Ross 	 * Compute length of converted UTF-16 string,
11807d1ffc32SGordon Ross 	 * NOT including null terminator (in bytes).
11813db3f65cSamw 	 */
11827d1ffc32SGordon Ross 	wcsbytes = smb_wcequiv_strlen(mbs);
11837d1ffc32SGordon Ross 	if (wcsbytes == (size_t)-1)
11847d1ffc32SGordon Ross 		return (DECODE_NO_MORE_DATA);
11857d1ffc32SGordon Ross 
11867d1ffc32SGordon Ross 	/*
11877d1ffc32SGordon Ross 	 * If repc not specified, put whole string + NULL,
11887d1ffc32SGordon Ross 	 * otherwise will truncate or pad as needed.
11897d1ffc32SGordon Ross 	 */
11907d1ffc32SGordon Ross 	if (repc <= 0)
11917d1ffc32SGordon Ross 		repc = wcsbytes + 2;
11927d1ffc32SGordon Ross 
11937d1ffc32SGordon Ross 	/*
11947d1ffc32SGordon Ross 	 * Convert into a temporary buffer
11957d1ffc32SGordon Ross 	 * Free wcsbuf before return.
11967d1ffc32SGordon Ross 	 */
11977d1ffc32SGordon Ross 	wcslen = wcsbytes / 2;
11987d1ffc32SGordon Ross 	wcsbuf = smb_mem_zalloc(wcsbytes + 2);
11997d1ffc32SGordon Ross 	ASSERT(wcsbuf != NULL);
12007d1ffc32SGordon Ross 	rlen = smb_mbstowcs(wcsbuf, mbs, wcslen);
12017d1ffc32SGordon Ross 	if (rlen == (size_t)-1) {
12027d1ffc32SGordon Ross 		rc = DECODE_NO_MORE_DATA;
12037d1ffc32SGordon Ross 		goto out;
12047d1ffc32SGordon Ross 	}
12057d1ffc32SGordon Ross 	if (rlen > wcslen)
12067d1ffc32SGordon Ross 		rlen = wcslen;
12077d1ffc32SGordon Ross 	wcsbuf[rlen] = 0;
12087d1ffc32SGordon Ross 
12097d1ffc32SGordon Ross 	/*
12107d1ffc32SGordon Ross 	 * Copy the converted string into the message,
12117d1ffc32SGordon Ross 	 * truncated or paded as required.  Preserve
12127d1ffc32SGordon Ross 	 * little-endian order while copying.
12137d1ffc32SGordon Ross 	 */
12147d1ffc32SGordon Ross 	wp = wcsbuf;
121525a9a7aaSGordon Ross 	while (repc >= sizeof (smb_wchar_t)) {
121625a9a7aaSGordon Ross 		if (mbc_marshal_make_room(mbc, sizeof (smb_wchar_t))) {
121725a9a7aaSGordon Ross 			rc = DECODE_NO_MORE_DATA;
121825a9a7aaSGordon Ross 			goto out;
121925a9a7aaSGordon Ross 		}
122025a9a7aaSGordon Ross 		wchar = LE_IN16(wp);
12213db3f65cSamw 		mbc_marshal_store_byte(mbc, wchar);
12223db3f65cSamw 		mbc_marshal_store_byte(mbc, wchar >> 8);
12237d1ffc32SGordon Ross 		if (wchar != 0)
12247d1ffc32SGordon Ross 			wp++;
12257d1ffc32SGordon Ross 		repc -= sizeof (smb_wchar_t);
12263db3f65cSamw 	}
122725a9a7aaSGordon Ross 	if (repc > 0) {
122825a9a7aaSGordon Ross 		if (mbc_marshal_make_room(mbc, 1)) {
122925a9a7aaSGordon Ross 			rc = DECODE_NO_MORE_DATA;
123025a9a7aaSGordon Ross 			goto out;
123125a9a7aaSGordon Ross 		}
12327d1ffc32SGordon Ross 		mbc_marshal_store_byte(mbc, 0);
123325a9a7aaSGordon Ross 	}
12347d1ffc32SGordon Ross 	rc = 0;
123525a9a7aaSGordon Ross 
12367d1ffc32SGordon Ross out:
12377d1ffc32SGordon Ross 	if (wcsbuf != NULL)
12387d1ffc32SGordon Ross 		smb_mem_free(wcsbuf);
12397d1ffc32SGordon Ross 	return (rc);
12403db3f65cSamw }
12413db3f65cSamw 
1242*897907ceSGordon Ross static void /*ARGSUSED*/
uiorefnoop(mbuf_t * m)1243*897907ceSGordon Ross uiorefnoop(mbuf_t *m)
1244a90cf9f2SGordon Ross {
1245a90cf9f2SGordon Ross }
1246a90cf9f2SGordon Ross 
12473db3f65cSamw static int
mbc_marshal_put_uio(mbuf_chain_t * mbc,struct uio * uio)12483db3f65cSamw mbc_marshal_put_uio(mbuf_chain_t *mbc, struct uio *uio)
12493db3f65cSamw {
12503db3f65cSamw 	mbuf_t		**t;
12513db3f65cSamw 	mbuf_t		*m = NULL;
12523db3f65cSamw 	struct iovec	*iov = uio->uio_iov;
12533db3f65cSamw 	int32_t		i, iov_cnt = uio->uio_iovcnt;
12543db3f65cSamw 
12553db3f65cSamw 	iov = uio->uio_iov;
12563db3f65cSamw 	t = &mbc->chain;
12573db3f65cSamw 	for (i = 0; i < iov_cnt; i++) {
12583db3f65cSamw 		MGET(m, M_WAIT, MT_DATA);
12593db3f65cSamw 		m->m_ext.ext_buf = iov->iov_base;
1260*897907ceSGordon Ross 		m->m_ext.ext_free = uiorefnoop;
12613db3f65cSamw 		m->m_data = m->m_ext.ext_buf;
12623db3f65cSamw 		m->m_flags |= M_EXT;
12633db3f65cSamw 		m->m_len = m->m_ext.ext_size = iov->iov_len;
12643db3f65cSamw 		mbc->max_bytes += m->m_len;
12653db3f65cSamw 		m->m_next = 0;
12663db3f65cSamw 		*t = m;
12673db3f65cSamw 		t = &m->m_next;
12683db3f65cSamw 		iov++;
12693db3f65cSamw 	}
12703db3f65cSamw 	return (0);
12713db3f65cSamw }
12723db3f65cSamw 
1273*897907ceSGordon Ross int smb_mbuf_put_copy_threshold = 128;
1274*897907ceSGordon Ross /*
1275*897907ceSGordon Ross  * Append an mbuf to the chain at chain_offset, with some optimizations:
1276*897907ceSGordon Ross  * If the chain is empty, just set the head (done).
1277*897907ceSGordon Ross  * If m is no larger than the copy threshold, copy.
1278*897907ceSGordon Ross  * Always consumes (or free's) the mbuf passed in.
1279*897907ceSGordon Ross  */
12803db3f65cSamw static int
mbc_marshal_put_mbufs(mbuf_chain_t * mbc,mbuf_t * mbuf)1281*897907ceSGordon Ross mbc_marshal_put_mbufs(mbuf_chain_t *mbc, mbuf_t *mbuf)
12823db3f65cSamw {
1283*897907ceSGordon Ross 	mbuf_t	*m;
1284*897907ceSGordon Ross 	int	bytes, rc;
12853db3f65cSamw 
1286*897907ceSGordon Ross 	/*
1287*897907ceSGordon Ross 	 * Length of mbuf(s) to be appended
1288*897907ceSGordon Ross 	 */
1289*897907ceSGordon Ross 	bytes = 0;
1290*897907ceSGordon Ross 	m = mbuf;
1291*897907ceSGordon Ross 	while (m != NULL) {
1292*897907ceSGordon Ross 		bytes += m->m_len;
1293*897907ceSGordon Ross 		m = m->m_next;
12943db3f65cSamw 	}
1295*897907ceSGordon Ross 	if (bytes == 0) {
1296*897907ceSGordon Ross 		m_freem(mbuf);
1297*897907ceSGordon Ross 		return (0);
12983db3f65cSamw 	}
1299*897907ceSGordon Ross 
1300*897907ceSGordon Ross 	/*
1301*897907ceSGordon Ross 	 * Check for space vs max_bytes
1302*897907ceSGordon Ross 	 */
1303*897907ceSGordon Ross 	if (!MBC_ROOM_FOR(mbc, bytes)) {
1304*897907ceSGordon Ross 		m_freem(mbuf);
1305*897907ceSGordon Ross 		return (EMSGSIZE);
1306*897907ceSGordon Ross 	}
1307*897907ceSGordon Ross 
1308*897907ceSGordon Ross 	/*
1309*897907ceSGordon Ross 	 * Empty mbc? (probably rare)
1310*897907ceSGordon Ross 	 */
1311*897907ceSGordon Ross 	if (mbc->chain == NULL) {
1312*897907ceSGordon Ross 		mbc->chain = mbuf;
13133db3f65cSamw 		mbc->chain_offset = bytes;
1314*897907ceSGordon Ross 		return (0);
13153db3f65cSamw 	}
1316*897907ceSGordon Ross 
1317*897907ceSGordon Ross 	/*
1318*897907ceSGordon Ross 	 * Copy optimization.  We've already checked that there's room
1319*897907ceSGordon Ross 	 * for the _put_mem operations, and that's the only error case
1320*897907ceSGordon Ross 	 * for that call, so just assert success and continue.
1321*897907ceSGordon Ross 	 */
1322*897907ceSGordon Ross 	if (bytes <= smb_mbuf_put_copy_threshold) {
1323*897907ceSGordon Ross 		m = mbuf;
1324*897907ceSGordon Ross 		while (m != NULL) {
1325*897907ceSGordon Ross 			rc = smb_mbc_put_mem(mbc, m->m_data, m->m_len);
1326*897907ceSGordon Ross 			ASSERT3S(rc, ==, 0);
1327*897907ceSGordon Ross 			m = m_free(m);
13283db3f65cSamw 		}
13293db3f65cSamw 		return (0);
13303db3f65cSamw 	}
13313db3f65cSamw 
1332*897907ceSGordon Ross 	/*
1333*897907ceSGordon Ross 	 * Trim existing chain and append
1334*897907ceSGordon Ross 	 */
1335*897907ceSGordon Ross 	smb_mbuf_trim(mbc->chain, mbc->chain_offset);
1336*897907ceSGordon Ross 	m = mbc->chain;
1337*897907ceSGordon Ross 	while (m->m_next != NULL)
1338*897907ceSGordon Ross 		m = m->m_next;
1339*897907ceSGordon Ross 	m->m_next = mbuf;
1340*897907ceSGordon Ross 	mbc->chain_offset += bytes;
1341*897907ceSGordon Ross 
1342*897907ceSGordon Ross 	return (0);
1343*897907ceSGordon Ross }
1344*897907ceSGordon Ross 
1345*897907ceSGordon Ross /*
1346*897907ceSGordon Ross  * Append a new mbc (nmbc) to the existing chain mbc
1347*897907ceSGordon Ross  * Assumes the new mbc has been "trimmed" to length.
1348*897907ceSGordon Ross  * (This ignores nmbc.chain_offset)
1349*897907ceSGordon Ross  *
1350*897907ceSGordon Ross  * Always consume or dispose of nmbc->chain
1351*897907ceSGordon Ross  */
13523db3f65cSamw static int
mbc_marshal_put_mbuf_chain(mbuf_chain_t * mbc,mbuf_chain_t * nmbc)13533db3f65cSamw mbc_marshal_put_mbuf_chain(mbuf_chain_t *mbc, mbuf_chain_t *nmbc)
13543db3f65cSamw {
1355*897907ceSGordon Ross 	int rc = 0;
1356*897907ceSGordon Ross 
1357*897907ceSGordon Ross 	if (nmbc->chain != NULL) {
1358*897907ceSGordon Ross 		rc = mbc_marshal_put_mbufs(mbc, nmbc->chain);
1359*897907ceSGordon Ross 		nmbc->chain = NULL;
13603db3f65cSamw 	}
1361*897907ceSGordon Ross 	return (rc);
13623db3f65cSamw }
13633db3f65cSamw 
13643db3f65cSamw static uint8_t
mbc_marshal_fetch_byte(mbuf_chain_t * mbc)13653db3f65cSamw mbc_marshal_fetch_byte(mbuf_chain_t *mbc)
13663db3f65cSamw {
13673db3f65cSamw 	uint8_t	data;
13683db3f65cSamw 	mbuf_t	*m = mbc->chain;
13693db3f65cSamw 	int32_t	offset = mbc->chain_offset;
13703db3f65cSamw 
13713db3f65cSamw 	while (offset >= m->m_len) {
13723db3f65cSamw 		offset -= m->m_len;
13733db3f65cSamw 		m = m->m_next;
13743db3f65cSamw 	}
13753db3f65cSamw 	data = ((uint8_t *)m->m_data)[offset];
13763db3f65cSamw 	mbc->chain_offset++;
13773db3f65cSamw 	return (data);
13783db3f65cSamw }
13793db3f65cSamw 
13803db3f65cSamw static int
mbc_marshal_get_char(mbuf_chain_t * mbc,uint8_t * data)13813db3f65cSamw mbc_marshal_get_char(mbuf_chain_t *mbc, uint8_t *data)
13823db3f65cSamw {
13833db3f65cSamw 	if (MBC_ROOM_FOR(mbc, sizeof (char)) == 0) {
13843db3f65cSamw 		/* Data will never be available */
13853db3f65cSamw 		return (DECODE_NO_MORE_DATA);
13863db3f65cSamw 	}
13873db3f65cSamw 	*data = mbc_marshal_fetch_byte(mbc);
13883db3f65cSamw 	return (0);
13893db3f65cSamw }
13903db3f65cSamw 
13913db3f65cSamw static int
mbc_marshal_get_short(mbuf_chain_t * mbc,uint16_t * data)13923db3f65cSamw mbc_marshal_get_short(mbuf_chain_t *mbc, uint16_t *data)
13933db3f65cSamw {
13943db3f65cSamw 	uint16_t	tmp;
13953db3f65cSamw 	mbuf_t		*m = mbc->chain;
13963db3f65cSamw 	int32_t		offset = mbc->chain_offset;
13973db3f65cSamw 
13983db3f65cSamw 	if (MBC_ROOM_FOR(mbc, sizeof (short)) == 0) {
13993db3f65cSamw 		/* Data will never be available */
14003db3f65cSamw 		return (DECODE_NO_MORE_DATA);
14013db3f65cSamw 	}
14023db3f65cSamw 
14033db3f65cSamw 	while (offset >= m->m_len) {
14043db3f65cSamw 		offset -= m->m_len;
14053db3f65cSamw 		m = m->m_next;
14063db3f65cSamw 	}
14073db3f65cSamw 	if ((m->m_len - offset) >= sizeof (short)) {
14083db3f65cSamw 		*data = LE_IN16(m->m_data + offset);
14093db3f65cSamw 		mbc->chain_offset += sizeof (short);
14103db3f65cSamw 	} else {
14113db3f65cSamw 		tmp = (uint16_t)mbc_marshal_fetch_byte(mbc);
14123db3f65cSamw 		tmp |= ((uint16_t)mbc_marshal_fetch_byte(mbc)) << 8;
14133db3f65cSamw 		*data = tmp;
14143db3f65cSamw 	}
14153db3f65cSamw 	return (0);
14163db3f65cSamw }
14173db3f65cSamw 
14183db3f65cSamw static int
mbc_marshal_get_long(mbuf_chain_t * mbc,uint32_t * data)14193db3f65cSamw mbc_marshal_get_long(mbuf_chain_t *mbc, uint32_t *data)
14203db3f65cSamw {
14213db3f65cSamw 	uint32_t	tmp;
14223db3f65cSamw 	mbuf_t		*m = mbc->chain;
14233db3f65cSamw 	int32_t		offset = mbc->chain_offset;
14243db3f65cSamw 
14253db3f65cSamw 	if (MBC_ROOM_FOR(mbc, sizeof (int32_t)) == 0) {
14263db3f65cSamw 		/* Data will never be available */
14273db3f65cSamw 		return (DECODE_NO_MORE_DATA);
14283db3f65cSamw 	}
14293db3f65cSamw 	while (offset >= m->m_len) {
14303db3f65cSamw 		offset -= m->m_len;
14313db3f65cSamw 		m = m->m_next;
14323db3f65cSamw 	}
14333db3f65cSamw 	if ((m->m_len - offset) >= sizeof (int32_t)) {
14343db3f65cSamw 		*data = LE_IN32(m->m_data + offset);
14353db3f65cSamw 		mbc->chain_offset += sizeof (int32_t);
14363db3f65cSamw 	} else {
14373db3f65cSamw 		tmp = (uint32_t)mbc_marshal_fetch_byte(mbc);
14383db3f65cSamw 		tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 8;
14393db3f65cSamw 		tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 16;
14403db3f65cSamw 		tmp |= ((uint32_t)mbc_marshal_fetch_byte(mbc)) << 24;
14413db3f65cSamw 		*data = tmp;
14423db3f65cSamw 	}
14433db3f65cSamw 	return (0);
14443db3f65cSamw }
14453db3f65cSamw 
14463db3f65cSamw static uint64_t
qswap(uint64_t ll)14473db3f65cSamw qswap(uint64_t ll)
14483db3f65cSamw {
14493db3f65cSamw 	uint64_t v;
14503db3f65cSamw 
14513db3f65cSamw 	v = ll >> 32;
14523db3f65cSamw 	v |= ll << 32;
14533db3f65cSamw 
14543db3f65cSamw 	return (v);
14553db3f65cSamw }
14563db3f65cSamw 
14573db3f65cSamw static int
mbc_marshal_get_odd_long_long(mbuf_chain_t * mbc,uint64_t * data)14583db3f65cSamw mbc_marshal_get_odd_long_long(mbuf_chain_t *mbc, uint64_t *data)
14593db3f65cSamw {
14603db3f65cSamw 	uint64_t	tmp;
14613db3f65cSamw 	mbuf_t		*m = mbc->chain;
14623db3f65cSamw 	int32_t		offset = mbc->chain_offset;
14633db3f65cSamw 
14643db3f65cSamw 	if (MBC_ROOM_FOR(mbc, sizeof (int64_t)) == 0) {
14653db3f65cSamw 		/* Data will never be available */
14663db3f65cSamw 		return (DECODE_NO_MORE_DATA);
14673db3f65cSamw 	}
14683db3f65cSamw 	while (offset >= m->m_len) {
14693db3f65cSamw 		offset -= m->m_len;
14703db3f65cSamw 		m = m->m_next;
14713db3f65cSamw 	}
14723db3f65cSamw 
14733db3f65cSamw 	if ((m->m_len - offset) >= sizeof (int64_t)) {
14743db3f65cSamw 		*data = qswap(LE_IN64(m->m_data + offset));
14753db3f65cSamw 		mbc->chain_offset += sizeof (int64_t);
14763db3f65cSamw 	} else {
14773db3f65cSamw 		tmp = (uint64_t)mbc_marshal_fetch_byte(mbc) << 32;
14783db3f65cSamw 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 40;
14793db3f65cSamw 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 48;
14803db3f65cSamw 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 56;
14813db3f65cSamw 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc);
14823db3f65cSamw 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 8;
14833db3f65cSamw 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 16;
14843db3f65cSamw 		tmp |= (uint64_t)mbc_marshal_fetch_byte(mbc) << 24;
14853db3f65cSamw 
14863db3f65cSamw 		*(uint64_t *)data = tmp;
14873db3f65cSamw 	}
14883db3f65cSamw 	return (0);
14893db3f65cSamw }
14903db3f65cSamw 
14913db3f65cSamw static int
mbc_marshal_get_long_long(mbuf_chain_t * mbc,uint64_t * data)14923db3f65cSamw mbc_marshal_get_long_long(mbuf_chain_t *mbc, uint64_t *data)
14933db3f65cSamw {
14943db3f65cSamw 	uint64_t	tmp;
14953db3f65cSamw 	mbuf_t		*m = mbc->chain;
14963db3f65cSamw 	int32_t		offset = mbc->chain_offset;
14973db3f65cSamw 
14983db3f65cSamw 	if (MBC_ROOM_FOR(mbc, sizeof (int64_t)) == 0) {
14993db3f65cSamw 		/* Data will never be available */
15003db3f65cSamw 		return (DECODE_NO_MORE_DATA);
15013db3f65cSamw 	}
15023db3f65cSamw 	while (offset >= m->m_len) {
15033db3f65cSamw 		offset -= m->m_len;
15043db3f65cSamw 		m = m->m_next;
15053db3f65cSamw 	}
15063db3f65cSamw 	if ((m->m_len - offset) >= sizeof (int64_t)) {
15073db3f65cSamw 		*data = LE_IN64(m->m_data + offset);
15083db3f65cSamw 		mbc->chain_offset += sizeof (int64_t);
15093db3f65cSamw 	} else {
15103db3f65cSamw 		tmp = (uint32_t)mbc_marshal_fetch_byte(mbc);
15113db3f65cSamw 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 8;
15123db3f65cSamw 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 16;
15133db3f65cSamw 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 24;
15143db3f65cSamw 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 32;
15153db3f65cSamw 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 40;
15163db3f65cSamw 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 48;
15173db3f65cSamw 		tmp |= ((uint64_t)mbc_marshal_fetch_byte(mbc)) << 56;
15183db3f65cSamw 		*(uint64_t *)data = tmp;
15193db3f65cSamw 	}
15203db3f65cSamw 	return (0);
15213db3f65cSamw }
15223db3f65cSamw 
15233db3f65cSamw /*
152407a6ae61SGordon Ross  * mbc_marshal_get_oem_string
15253db3f65cSamw  *
152607a6ae61SGordon Ross  * Decode an OEM string, returning its UTF-8 form in strpp,
152707a6ae61SGordon Ross  * allocated using smb_srm_zalloc (automatically freed).
15287d1ffc32SGordon Ross  * If max_bytes != 0, consume at most max_bytes of the mbc.
15297d1ffc32SGordon Ross  * See also: msgbuf_get_oem_string
15303db3f65cSamw  */
15313db3f65cSamw static int
mbc_marshal_get_oem_string(smb_request_t * sr,mbuf_chain_t * mbc,char ** strpp,int max_bytes)15327d1ffc32SGordon Ross mbc_marshal_get_oem_string(smb_request_t *sr,
15337d1ffc32SGordon Ross     mbuf_chain_t *mbc, char **strpp, int max_bytes)
15343db3f65cSamw {
15357d1ffc32SGordon Ross 	char		*mbs;
15367d1ffc32SGordon Ross 	uint8_t		*oembuf = NULL;
15377d1ffc32SGordon Ross 	int		oemlen, oemmax;
15387d1ffc32SGordon Ross 	int		mbsmax;
15397d1ffc32SGordon Ross 	int		rlen;
15407d1ffc32SGordon Ross 	int		rc;
15413db3f65cSamw 
15427d1ffc32SGordon Ross 	if (max_bytes == 0)
15437d1ffc32SGordon Ross 		max_bytes = 0xffff;
15443db3f65cSamw 
15453db3f65cSamw 	/*
15467d1ffc32SGordon Ross 	 * Get the OtW data into a temporary buffer.
15477d1ffc32SGordon Ross 	 * Free oembuf before return.
15483db3f65cSamw 	 */
15497d1ffc32SGordon Ross 	oemlen = 0;
15507d1ffc32SGordon Ross 	oemmax = MALLOC_QUANTUM;
15517d1ffc32SGordon Ross 	oembuf = smb_mem_alloc(oemmax);
15527d1ffc32SGordon Ross 	for (;;) {
15537d1ffc32SGordon Ross 		uint8_t ch;
155407a6ae61SGordon Ross 
15557d1ffc32SGordon Ross 		if (oemlen >= max_bytes)
15567d1ffc32SGordon Ross 			break;
15577d1ffc32SGordon Ross 		if ((oemlen + 2) >= oemmax) {
15587d1ffc32SGordon Ross 			oemmax += MALLOC_QUANTUM;
15597d1ffc32SGordon Ross 			oembuf = smb_mem_realloc(oembuf, oemmax);
15607d1ffc32SGordon Ross 		}
15617d1ffc32SGordon Ross 		if (mbc_marshal_get_char(mbc, &ch) != 0) {
15627d1ffc32SGordon Ross 			rc = DECODE_NO_MORE_DATA;
15637d1ffc32SGordon Ross 			goto out;
15647d1ffc32SGordon Ross 		}
15657d1ffc32SGordon Ross 		if (ch == 0)
15667d1ffc32SGordon Ross 			break;
15677d1ffc32SGordon Ross 		oembuf[oemlen++] = ch;
15687d1ffc32SGordon Ross 	}
15697d1ffc32SGordon Ross 	oembuf[oemlen] = '\0';
15707d1ffc32SGordon Ross 
15717d1ffc32SGordon Ross 	/*
15727d1ffc32SGordon Ross 	 * Get the buffer we'll return and convert to UTF-8.
15737d1ffc32SGordon Ross 	 * May take as much as double the space.
15747d1ffc32SGordon Ross 	 */
15757d1ffc32SGordon Ross 	mbsmax = oemlen * 2;
15767d1ffc32SGordon Ross 	mbs = smb_srm_zalloc(sr, mbsmax + 1);
15777d1ffc32SGordon Ross 	ASSERT(mbs != NULL);
15787d1ffc32SGordon Ross 	rlen = smb_oemtombs(mbs, oembuf, mbsmax);
15797d1ffc32SGordon Ross 	if (rlen < 0) {
15807d1ffc32SGordon Ross 		rc = DECODE_NO_MORE_DATA;
15817d1ffc32SGordon Ross 		goto out;
15827d1ffc32SGordon Ross 	}
15837d1ffc32SGordon Ross 	if (rlen > mbsmax)
15847d1ffc32SGordon Ross 		rlen = mbsmax;
15857d1ffc32SGordon Ross 	mbs[rlen] = '\0';
15867d1ffc32SGordon Ross 	*strpp = mbs;
15877d1ffc32SGordon Ross 	rc = 0;
15887d1ffc32SGordon Ross 
15897d1ffc32SGordon Ross out:
15907d1ffc32SGordon Ross 	if (oembuf != NULL)
15917d1ffc32SGordon Ross 		smb_mem_free(oembuf);
15927d1ffc32SGordon Ross 	return (rc);
15933db3f65cSamw }
15943db3f65cSamw 
159507a6ae61SGordon Ross /*
159607a6ae61SGordon Ross  * mbc_marshal_get_unicode_string
159707a6ae61SGordon Ross  *
159807a6ae61SGordon Ross  * Decode a UTF-16 string, returning its UTF-8 form in strpp,
159907a6ae61SGordon Ross  * allocated using smb_srm_zalloc (automatically freed).
16007d1ffc32SGordon Ross  * If max_bytes != 0, consume at most max_bytes of the mbc.
16017d1ffc32SGordon Ross  * See also: msgbuf_get_unicode_string
160207a6ae61SGordon Ross  */
16033db3f65cSamw static int
mbc_marshal_get_unicode_string(smb_request_t * sr,mbuf_chain_t * mbc,char ** strpp,int max_bytes)1604bbf6f00cSJordan Brown mbc_marshal_get_unicode_string(smb_request_t *sr,
16057d1ffc32SGordon Ross     mbuf_chain_t *mbc, char **strpp, int max_bytes)
16063db3f65cSamw {
16077d1ffc32SGordon Ross 	char		*mbs;
16087d1ffc32SGordon Ross 	uint16_t	*wcsbuf = NULL;
16097d1ffc32SGordon Ross 	int		wcslen;		// wchar count
16107d1ffc32SGordon Ross 	int		wcsmax;		// byte count
16117d1ffc32SGordon Ross 	size_t		mbsmax;
16127d1ffc32SGordon Ross 	size_t		rlen;
16137d1ffc32SGordon Ross 	int		rc;
16143db3f65cSamw 
16157d1ffc32SGordon Ross 	if (max_bytes == 0)
16167d1ffc32SGordon Ross 		max_bytes = 0xffff;
16173db3f65cSamw 
16187d1ffc32SGordon Ross 	/*
16197d1ffc32SGordon Ross 	 * Unicode strings are always word aligned.
16207d1ffc32SGordon Ross 	 */
16217d1ffc32SGordon Ross 	if (mbc->chain_offset & 1) {
16227d1ffc32SGordon Ross 		if (MBC_ROOM_FOR(mbc, sizeof (char)) == 0)
16233db3f65cSamw 			return (DECODE_NO_MORE_DATA);
16247d1ffc32SGordon Ross 		mbc->chain_offset++;
16253db3f65cSamw 	}
16267d1ffc32SGordon Ross 
16277d1ffc32SGordon Ross 	/*
16287d1ffc32SGordon Ross 	 * Get the OtW data into a temporary buffer.
16297d1ffc32SGordon Ross 	 * Free wcsbuf before return.
16307d1ffc32SGordon Ross 	 */
16317d1ffc32SGordon Ross 	wcslen = 0;
16327d1ffc32SGordon Ross 	wcsmax = MALLOC_QUANTUM;
16337d1ffc32SGordon Ross 	wcsbuf = smb_mem_alloc(wcsmax);
16347d1ffc32SGordon Ross 	for (;;) {
16357d1ffc32SGordon Ross 		uint16_t	wchar;
16367d1ffc32SGordon Ross 
16377d1ffc32SGordon Ross 		if ((wcslen * 2) >= max_bytes)
16387d1ffc32SGordon Ross 			break;
16397d1ffc32SGordon Ross 		if (((wcslen * 2) + 4) >= wcsmax) {
16407d1ffc32SGordon Ross 			wcsmax += MALLOC_QUANTUM;
16417d1ffc32SGordon Ross 			wcsbuf = smb_mem_realloc(wcsbuf, wcsmax);
16423db3f65cSamw 		}
16437d1ffc32SGordon Ross 		if (mbc_marshal_get_short(mbc, &wchar) != 0) {
16447d1ffc32SGordon Ross 			rc = DECODE_NO_MORE_DATA;
16457d1ffc32SGordon Ross 			goto out;
16467d1ffc32SGordon Ross 		}
16477d1ffc32SGordon Ross 		if (wchar == 0)
16487d1ffc32SGordon Ross 			break;
16497d1ffc32SGordon Ross 		/* Keep in little-endian form. */
16507d1ffc32SGordon Ross 		LE_OUT16(wcsbuf + wcslen, wchar);
16517d1ffc32SGordon Ross 		wcslen++;
16527d1ffc32SGordon Ross 	}
16537d1ffc32SGordon Ross 	wcsbuf[wcslen] = 0;
16547d1ffc32SGordon Ross 
16557d1ffc32SGordon Ross 	/*
16567d1ffc32SGordon Ross 	 * Get the buffer we'll return and convert to UTF-8.
16577d1ffc32SGordon Ross 	 * May take as much 4X number of wide chars.
16587d1ffc32SGordon Ross 	 */
16597d1ffc32SGordon Ross 	mbsmax = wcslen * MTS_MB_CUR_MAX;
16607d1ffc32SGordon Ross 	mbs = smb_srm_zalloc(sr, mbsmax + 1);
16617d1ffc32SGordon Ross 	ASSERT(mbs != NULL);
16627d1ffc32SGordon Ross 	rlen = smb_wcstombs(mbs, wcsbuf, mbsmax);
16637d1ffc32SGordon Ross 	if (rlen == (size_t)-1) {
16647d1ffc32SGordon Ross 		rc = DECODE_NO_MORE_DATA;
16657d1ffc32SGordon Ross 		goto out;
16667d1ffc32SGordon Ross 	}
16677d1ffc32SGordon Ross 	if (rlen > mbsmax)
16687d1ffc32SGordon Ross 		rlen = mbsmax;
16697d1ffc32SGordon Ross 	mbs[rlen] = '\0';
16707d1ffc32SGordon Ross 	*strpp = mbs;
16717d1ffc32SGordon Ross 	rc = 0;
16727d1ffc32SGordon Ross 
16737d1ffc32SGordon Ross out:
16747d1ffc32SGordon Ross 	if (wcsbuf != NULL)
16757d1ffc32SGordon Ross 		smb_mem_free(wcsbuf);
16767d1ffc32SGordon Ross 	return (rc);
16773db3f65cSamw }
16783db3f65cSamw 
16793db3f65cSamw static int /*ARGSUSED*/
mbc_marshal_get_mbufs(mbuf_chain_t * mbc,int32_t bytes,mbuf_t ** m)16803db3f65cSamw mbc_marshal_get_mbufs(mbuf_chain_t *mbc, int32_t bytes, mbuf_t **m)
16813db3f65cSamw {
16827f3ef643SGordon Ross 	*m = NULL;
16833db3f65cSamw 	if (MBC_ROOM_FOR(mbc, bytes) == 0) {
16843db3f65cSamw 		/* Data will never be available */
16853db3f65cSamw 		return (DECODE_NO_MORE_DATA);
16863db3f65cSamw 	}
16877f3ef643SGordon Ross 	/* not yet implemented */
16887f3ef643SGordon Ross 	return (-1);
16893db3f65cSamw }
16903db3f65cSamw 
16913db3f65cSamw static int
mbc_marshal_get_mbuf_chain(mbuf_chain_t * mbc,int32_t bytes,mbuf_chain_t * nmbc)16923db3f65cSamw mbc_marshal_get_mbuf_chain(mbuf_chain_t *mbc, int32_t bytes, mbuf_chain_t *nmbc)
16933db3f65cSamw {
16943db3f65cSamw 	int	rc;
16953db3f65cSamw 	mbuf_t	*m;
16963db3f65cSamw 
16973db3f65cSamw 	if (bytes == 0) {
16983db3f65cSamw 		/* Get all the rest */
16993db3f65cSamw 		bytes = mbc->max_bytes - mbc->chain_offset;
17003db3f65cSamw 	}
17013db3f65cSamw 
17023db3f65cSamw 	MBC_SETUP(nmbc, mbc->max_bytes);
17033db3f65cSamw 	if ((rc = mbc_marshal_get_mbufs(mbc, bytes, &m)) != 0) {
17043db3f65cSamw 		if (m)
17053db3f65cSamw 			m_freem(m);
17063db3f65cSamw 		return (rc);
17073db3f65cSamw 	}
17083db3f65cSamw 	nmbc->chain = m;
17093db3f65cSamw 	while (m != 0) {
17103db3f65cSamw 		bytes += m->m_len;
17113db3f65cSamw 		m = m->m_next;
17123db3f65cSamw 	}
17133db3f65cSamw 	nmbc->max_bytes = bytes;
17143db3f65cSamw 	return (0);
17153db3f65cSamw }
17163db3f65cSamw 
17173db3f65cSamw static int
mbc_marshal_get_uio(mbuf_chain_t * mbc,struct uio * uio)17183db3f65cSamw mbc_marshal_get_uio(mbuf_chain_t *mbc, struct uio *uio)
17193db3f65cSamw {
17203db3f65cSamw 	int		i, offset;
17213db3f65cSamw 	int32_t		bytes = uio->uio_resid;
17223db3f65cSamw 	int32_t		remainder;
17233db3f65cSamw 	struct iovec	*iov;
17243db3f65cSamw 	mbuf_t		*m;
17253db3f65cSamw 
17263db3f65cSamw 	/*
17273db3f65cSamw 	 * The residual count is tested because in the case of write requests
17283db3f65cSamw 	 * with no data (smbtorture RAW-WRITE test will generate that type of
17293db3f65cSamw 	 * request) this function is called with a residual count of zero
17303db3f65cSamw 	 * bytes.
17313db3f65cSamw 	 */
17327b6a044aSjose borrego 	if (bytes != 0) {
17333db3f65cSamw 		iov = uio->uio_iov;
17343db3f65cSamw 		uio->uio_segflg = UIO_SYSSPACE;
1735f96bd5c8SAlan Wright 		uio->uio_extflg = UIO_COPY_DEFAULT;
17363db3f65cSamw 
17373db3f65cSamw 		if (MBC_ROOM_FOR(mbc, bytes) == 0) {
17383db3f65cSamw 			/* Data will never be available */
17393db3f65cSamw 			return (DECODE_NO_MORE_DATA);
17403db3f65cSamw 		}
17413db3f65cSamw 
17423db3f65cSamw 		m = mbc->chain;
17433db3f65cSamw 		offset = mbc->chain_offset;
17443db3f65cSamw 		while (offset >= m->m_len) {
17453db3f65cSamw 			offset -= m->m_len;
17463db3f65cSamw 			m = m->m_next;
17473db3f65cSamw 			ASSERT((offset == 0) || (offset && m));
17483db3f65cSamw 		}
17493db3f65cSamw 
17503db3f65cSamw 		for (i = 0; (bytes > 0) && (i < uio->uio_iovcnt); i++) {
17513db3f65cSamw 			iov[i].iov_base = &m->m_data[offset];
17523db3f65cSamw 			remainder = m->m_len - offset;
17533db3f65cSamw 			if (remainder >= bytes) {
17543db3f65cSamw 				iov[i].iov_len = bytes;
17553db3f65cSamw 				mbc->chain_offset += bytes;
17567b6a044aSjose borrego 				uio->uio_iovcnt = i + 1;
17577b6a044aSjose borrego 				return (0);
17583db3f65cSamw 			}
17593db3f65cSamw 			iov[i].iov_len = remainder;
17603db3f65cSamw 			mbc->chain_offset += remainder;
17613db3f65cSamw 			bytes -= remainder;
17623db3f65cSamw 			m = m->m_next;
17633db3f65cSamw 			offset = 0;
17643db3f65cSamw 		}
17653db3f65cSamw 		return (DECODE_NO_MORE_DATA);
17663db3f65cSamw 	}
17673db3f65cSamw 	return (0);
17683db3f65cSamw }
17693db3f65cSamw 
17703db3f65cSamw static int
mbc_marshal_get_skip(mbuf_chain_t * mbc,uint_t skip)17713db3f65cSamw mbc_marshal_get_skip(mbuf_chain_t *mbc, uint_t skip)
17723db3f65cSamw {
17733db3f65cSamw 	if (MBC_ROOM_FOR(mbc, skip) == 0)
17743db3f65cSamw 		return (DECODE_NO_MORE_DATA);
17753db3f65cSamw 	mbc->chain_offset += skip;
17763db3f65cSamw 	return (0);
17773db3f65cSamw }
1778