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