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