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