xref: /titanic_51/usr/src/lib/libsmbfs/smb/mbuf.c (revision 02d09e03eb27f3a2dc299de704e45dae5173f43f)
14bff34e3Sthurlow /*
24bff34e3Sthurlow  * Copyright (c) 2000, Boris Popov
34bff34e3Sthurlow  * All rights reserved.
44bff34e3Sthurlow  *
54bff34e3Sthurlow  * Redistribution and use in source and binary forms, with or without
64bff34e3Sthurlow  * modification, are permitted provided that the following conditions
74bff34e3Sthurlow  * are met:
84bff34e3Sthurlow  * 1. Redistributions of source code must retain the above copyright
94bff34e3Sthurlow  *    notice, this list of conditions and the following disclaimer.
104bff34e3Sthurlow  * 2. Redistributions in binary form must reproduce the above copyright
114bff34e3Sthurlow  *    notice, this list of conditions and the following disclaimer in the
124bff34e3Sthurlow  *    documentation and/or other materials provided with the distribution.
134bff34e3Sthurlow  * 3. All advertising materials mentioning features or use of this software
144bff34e3Sthurlow  *    must display the following acknowledgement:
154bff34e3Sthurlow  *    This product includes software developed by Boris Popov.
164bff34e3Sthurlow  * 4. Neither the name of the author nor the names of any co-contributors
174bff34e3Sthurlow  *    may be used to endorse or promote products derived from this software
184bff34e3Sthurlow  *    without specific prior written permission.
194bff34e3Sthurlow  *
204bff34e3Sthurlow  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
214bff34e3Sthurlow  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
224bff34e3Sthurlow  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
234bff34e3Sthurlow  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
244bff34e3Sthurlow  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
254bff34e3Sthurlow  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
264bff34e3Sthurlow  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
274bff34e3Sthurlow  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
284bff34e3Sthurlow  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
294bff34e3Sthurlow  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
304bff34e3Sthurlow  * SUCH DAMAGE.
314bff34e3Sthurlow  *
324bff34e3Sthurlow  * $Id: mbuf.c,v 1.3 2004/12/13 00:25:22 lindak Exp $
334bff34e3Sthurlow  */
344bff34e3Sthurlow 
359c9af259SGordon Ross /*
36613a2f6bSGordon Ross  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
379c9af259SGordon Ross  * Use is subject to license terms.
389c9af259SGordon Ross  */
394bff34e3Sthurlow 
404bff34e3Sthurlow #include <sys/types.h>
414bff34e3Sthurlow #include <ctype.h>
424bff34e3Sthurlow #include <errno.h>
434bff34e3Sthurlow #include <stdio.h>
444bff34e3Sthurlow #include <stdlib.h>
454bff34e3Sthurlow #include <string.h>
464bff34e3Sthurlow #include <strings.h>
474bff34e3Sthurlow #include <libintl.h>
487568150aSgwr #include <assert.h>
494bff34e3Sthurlow 
504bff34e3Sthurlow #include <netsmb/smb_lib.h>
514bff34e3Sthurlow #include <netsmb/mchain.h>
524bff34e3Sthurlow 
539c9af259SGordon Ross #include "private.h"
54613a2f6bSGordon Ross #include "charsets.h"
554bff34e3Sthurlow 
56*02d09e03SGordon Ross /*
57*02d09e03SGordon Ross  * Note: Leaving a little space (8 bytes) between the
58*02d09e03SGordon Ross  * mbuf header and the start of the data so we can
59*02d09e03SGordon Ross  * prepend a NetBIOS header in that space.
60*02d09e03SGordon Ross  */
61*02d09e03SGordon Ross #define	M_ALIGNFACTOR	(sizeof (long))
62*02d09e03SGordon Ross #define	M_ALIGN(len)	(((len) + M_ALIGNFACTOR - 1) & ~(M_ALIGNFACTOR - 1))
63*02d09e03SGordon Ross #define	M_BASESIZE	(sizeof (struct mbuf) + 8)
64*02d09e03SGordon Ross #define	M_MINSIZE	(1024 - M_BASESIZE)
65*02d09e03SGordon Ross #define	M_TOP(m)	((char *)(m) + M_BASESIZE)
66*02d09e03SGordon Ross #define	M_TRAILINGSPACE(m) ((m)->m_maxlen - (m)->m_len)
67*02d09e03SGordon Ross 
68*02d09e03SGordon Ross int
69*02d09e03SGordon Ross m_get(int len, struct mbuf **mpp)
704bff34e3Sthurlow {
714bff34e3Sthurlow 	struct mbuf *m;
724bff34e3Sthurlow 
737568150aSgwr 	assert(len < 0x100000); /* sanity */
747568150aSgwr 
754bff34e3Sthurlow 	len = M_ALIGN(len);
764bff34e3Sthurlow 	if (len < M_MINSIZE)
774bff34e3Sthurlow 		len = M_MINSIZE;
784bff34e3Sthurlow 	m = malloc(M_BASESIZE + len);
794bff34e3Sthurlow 	if (m == NULL)
804bff34e3Sthurlow 		return (ENOMEM);
814bff34e3Sthurlow 	bzero(m, M_BASESIZE + len);
824bff34e3Sthurlow 	m->m_maxlen = len;
834bff34e3Sthurlow 	m->m_data = M_TOP(m);
844bff34e3Sthurlow 	*mpp = m;
854bff34e3Sthurlow 	return (0);
864bff34e3Sthurlow }
874bff34e3Sthurlow 
884bff34e3Sthurlow static void
894bff34e3Sthurlow m_free(struct mbuf *m)
904bff34e3Sthurlow {
914bff34e3Sthurlow 	free(m);
924bff34e3Sthurlow }
934bff34e3Sthurlow 
94613a2f6bSGordon Ross void
954bff34e3Sthurlow m_freem(struct mbuf *m0)
964bff34e3Sthurlow {
974bff34e3Sthurlow 	struct mbuf *m;
984bff34e3Sthurlow 
994bff34e3Sthurlow 	while (m0) {
1004bff34e3Sthurlow 		m = m0->m_next;
1014bff34e3Sthurlow 		m_free(m0);
1024bff34e3Sthurlow 		m0 = m;
1034bff34e3Sthurlow 	}
1044bff34e3Sthurlow }
1054bff34e3Sthurlow 
106613a2f6bSGordon Ross size_t
1074bff34e3Sthurlow m_totlen(struct mbuf *m0)
1084bff34e3Sthurlow {
1094bff34e3Sthurlow 	struct mbuf *m = m0;
1104bff34e3Sthurlow 	int len = 0;
1114bff34e3Sthurlow 
1124bff34e3Sthurlow 	while (m) {
1134bff34e3Sthurlow 		len += m->m_len;
1144bff34e3Sthurlow 		m = m->m_next;
1154bff34e3Sthurlow 	}
1164bff34e3Sthurlow 	return (len);
1174bff34e3Sthurlow }
1184bff34e3Sthurlow 
1194bff34e3Sthurlow int
1204bff34e3Sthurlow m_lineup(struct mbuf *m0, struct mbuf **mpp)
1214bff34e3Sthurlow {
1224bff34e3Sthurlow 	struct mbuf *nm, *m;
1234bff34e3Sthurlow 	char *dp;
1244bff34e3Sthurlow 	size_t len;
1254bff34e3Sthurlow 	int error;
1264bff34e3Sthurlow 
1274bff34e3Sthurlow 	if (m0->m_next == NULL) {
1284bff34e3Sthurlow 		*mpp = m0;
1294bff34e3Sthurlow 		return (0);
1304bff34e3Sthurlow 	}
1314bff34e3Sthurlow 	if ((error = m_get(m_totlen(m0), &nm)) != 0)
1324bff34e3Sthurlow 		return (error);
1334bff34e3Sthurlow 	dp = mtod(nm, char *);
1344bff34e3Sthurlow 	while (m0) {
1354bff34e3Sthurlow 		len = m0->m_len;
1364bff34e3Sthurlow 		bcopy(m0->m_data, dp, len);
1374bff34e3Sthurlow 		dp += len;
1384bff34e3Sthurlow 		m = m0->m_next;
1394bff34e3Sthurlow 		m_free(m0);
1404bff34e3Sthurlow 		m0 = m;
1414bff34e3Sthurlow 	}
1424bff34e3Sthurlow 	*mpp = nm;
1434bff34e3Sthurlow 	return (0);
1444bff34e3Sthurlow }
1454bff34e3Sthurlow 
1464bff34e3Sthurlow int
147*02d09e03SGordon Ross mb_init(struct mbdata *mbp)
148*02d09e03SGordon Ross {
149*02d09e03SGordon Ross 	return (mb_init_sz(mbp, M_MINSIZE));
150*02d09e03SGordon Ross }
151*02d09e03SGordon Ross 
152*02d09e03SGordon Ross int
153*02d09e03SGordon Ross mb_init_sz(struct mbdata *mbp, int size)
1544bff34e3Sthurlow {
1554bff34e3Sthurlow 	struct mbuf *m;
1564bff34e3Sthurlow 	int error;
1574bff34e3Sthurlow 
1584bff34e3Sthurlow 	if ((error = m_get(size, &m)) != 0)
1594bff34e3Sthurlow 		return (error);
160*02d09e03SGordon Ross 	mb_initm(mbp, m);
161*02d09e03SGordon Ross 	return (0);
1624bff34e3Sthurlow }
1634bff34e3Sthurlow 
164*02d09e03SGordon Ross void
1654bff34e3Sthurlow mb_initm(struct mbdata *mbp, struct mbuf *m)
1664bff34e3Sthurlow {
1674bff34e3Sthurlow 	bzero(mbp, sizeof (*mbp));
1684bff34e3Sthurlow 	mbp->mb_top = mbp->mb_cur = m;
1694bff34e3Sthurlow 	mbp->mb_pos = mtod(m, char *);
1704bff34e3Sthurlow }
1714bff34e3Sthurlow 
172*02d09e03SGordon Ross void
1734bff34e3Sthurlow mb_done(struct mbdata *mbp)
1744bff34e3Sthurlow {
1754bff34e3Sthurlow 	if (mbp->mb_top) {
1764bff34e3Sthurlow 		m_freem(mbp->mb_top);
1774bff34e3Sthurlow 		mbp->mb_top = NULL;
1784bff34e3Sthurlow 	}
1794bff34e3Sthurlow }
1804bff34e3Sthurlow 
1814bff34e3Sthurlow int
182*02d09e03SGordon Ross m_getm(struct mbuf *top, int len, struct mbuf **mpp)
1834bff34e3Sthurlow {
1844bff34e3Sthurlow 	struct mbuf *m, *mp;
1857568150aSgwr 	int  error, ts;
1864bff34e3Sthurlow 
1874bff34e3Sthurlow 	for (mp = top; ; mp = mp->m_next) {
1887568150aSgwr 		ts = M_TRAILINGSPACE(mp);
1897568150aSgwr 		if (len <= ts)
1907568150aSgwr 			goto out;
1917568150aSgwr 		len -= ts;
1924bff34e3Sthurlow 		if (mp->m_next == NULL)
1934bff34e3Sthurlow 			break;
1944bff34e3Sthurlow 
1954bff34e3Sthurlow 	}
1964bff34e3Sthurlow 	if (len > 0) {
1974bff34e3Sthurlow 		if ((error = m_get(len, &m)) != 0)
1984bff34e3Sthurlow 			return (error);
1994bff34e3Sthurlow 		mp->m_next = m;
2004bff34e3Sthurlow 	}
2017568150aSgwr out:
2024bff34e3Sthurlow 	*mpp = top;
2034bff34e3Sthurlow 	return (0);
2044bff34e3Sthurlow }
2054bff34e3Sthurlow 
2064bff34e3Sthurlow /*
2074bff34e3Sthurlow  * Routines to put data in a buffer
2084bff34e3Sthurlow  */
2094bff34e3Sthurlow 
210*02d09e03SGordon Ross void *
211*02d09e03SGordon Ross mb_reserve(mbchain_t *mbp, int size)
212*02d09e03SGordon Ross {
213*02d09e03SGordon Ross 	char *p;
214*02d09e03SGordon Ross 
215*02d09e03SGordon Ross 	if (mb_fit(mbp, size, &p) != 0)
216*02d09e03SGordon Ross 		return (NULL);
217*02d09e03SGordon Ross 
218*02d09e03SGordon Ross 	return (p);
219*02d09e03SGordon Ross }
220*02d09e03SGordon Ross 
2214bff34e3Sthurlow /*
2224bff34e3Sthurlow  * Check if object of size 'size' fit to the current position and
2234bff34e3Sthurlow  * allocate new mbuf if not. Advance pointers and increase length of mbuf(s).
2244bff34e3Sthurlow  * Return pointer to the object placeholder or NULL if any error occured.
2254bff34e3Sthurlow  */
2264bff34e3Sthurlow int
227*02d09e03SGordon Ross mb_fit(mbchain_t *mbp, int size, char **pp)
2284bff34e3Sthurlow {
2294bff34e3Sthurlow 	struct mbuf *m, *mn;
2304bff34e3Sthurlow 	int error;
2314bff34e3Sthurlow 
2324bff34e3Sthurlow 	m = mbp->mb_cur;
2334bff34e3Sthurlow 	if (M_TRAILINGSPACE(m) < (int)size) {
2344bff34e3Sthurlow 		if ((error = m_get(size, &mn)) != 0)
2354bff34e3Sthurlow 			return (error);
2364bff34e3Sthurlow 		mbp->mb_pos = mtod(mn, char *);
2374bff34e3Sthurlow 		mbp->mb_cur = m->m_next = mn;
2384bff34e3Sthurlow 		m = mn;
2394bff34e3Sthurlow 	}
2404bff34e3Sthurlow 	m->m_len += size;
2414bff34e3Sthurlow 	*pp = mbp->mb_pos;
2424bff34e3Sthurlow 	mbp->mb_pos += size;
2434bff34e3Sthurlow 	mbp->mb_count += size;
2444bff34e3Sthurlow 	return (0);
2454bff34e3Sthurlow }
2464bff34e3Sthurlow 
2474bff34e3Sthurlow int
248*02d09e03SGordon Ross mb_put_uint8(mbchain_t *mbp, uint8_t x)
2494bff34e3Sthurlow {
2509c9af259SGordon Ross 	uint8_t y = x;
251*02d09e03SGordon Ross 	return (mb_put_mem(mbp, &y, sizeof (y), MB_MINLINE));
2524bff34e3Sthurlow }
2534bff34e3Sthurlow 
2544bff34e3Sthurlow int
255*02d09e03SGordon Ross mb_put_uint16be(mbchain_t *mbp, uint16_t x)
2564bff34e3Sthurlow {
2579c9af259SGordon Ross 	uint16_t y = htobes(x);
258*02d09e03SGordon Ross 	return (mb_put_mem(mbp, &y, sizeof (y), MB_MINLINE));
2594bff34e3Sthurlow }
2604bff34e3Sthurlow 
2614bff34e3Sthurlow int
262*02d09e03SGordon Ross mb_put_uint16le(mbchain_t *mbp, uint16_t x)
2634bff34e3Sthurlow {
2649c9af259SGordon Ross 	uint16_t y = htoles(x);
265*02d09e03SGordon Ross 	return (mb_put_mem(mbp, &y, sizeof (y), MB_MINLINE));
2664bff34e3Sthurlow }
2674bff34e3Sthurlow 
2684bff34e3Sthurlow int
269*02d09e03SGordon Ross mb_put_uint32be(mbchain_t *mbp, uint32_t x)
2704bff34e3Sthurlow {
2719c9af259SGordon Ross 	uint32_t y = htobel(x);
272*02d09e03SGordon Ross 	return (mb_put_mem(mbp, &y, sizeof (y), MB_MINLINE));
2734bff34e3Sthurlow }
2744bff34e3Sthurlow 
2754bff34e3Sthurlow int
276*02d09e03SGordon Ross mb_put_uint32le(mbchain_t *mbp, uint32_t x)
2774bff34e3Sthurlow {
2789c9af259SGordon Ross 	uint32_t y = htolel(x);
279*02d09e03SGordon Ross 	return (mb_put_mem(mbp, &y, sizeof (y), MB_MINLINE));
2804bff34e3Sthurlow }
2814bff34e3Sthurlow 
2824bff34e3Sthurlow int
283*02d09e03SGordon Ross mb_put_uint64be(mbchain_t *mbp, uint64_t x)
2844bff34e3Sthurlow {
2859c9af259SGordon Ross 	uint64_t y = htobeq(x);
286*02d09e03SGordon Ross 	return (mb_put_mem(mbp, &y, sizeof (y), MB_MINLINE));
2874bff34e3Sthurlow }
2884bff34e3Sthurlow 
2894bff34e3Sthurlow int
290*02d09e03SGordon Ross mb_put_uint64le(mbchain_t *mbp, uint64_t x)
2914bff34e3Sthurlow {
2929c9af259SGordon Ross 	uint64_t y = htoleq(x);
293*02d09e03SGordon Ross 	return (mb_put_mem(mbp, &y, sizeof (y), MB_MINLINE));
2944bff34e3Sthurlow }
2954bff34e3Sthurlow 
296*02d09e03SGordon Ross /* ARGSUSED */
2974bff34e3Sthurlow int
298*02d09e03SGordon Ross mb_put_mem(mbchain_t *mbp, const void *vmem, int size, int type)
2994bff34e3Sthurlow {
3004bff34e3Sthurlow 	struct mbuf *m;
301613a2f6bSGordon Ross 	const char *src;
3024bff34e3Sthurlow 	char  *dst;
3034bff34e3Sthurlow 	size_t cplen;
3044bff34e3Sthurlow 	int error;
3054bff34e3Sthurlow 
3064bff34e3Sthurlow 	if (size == 0)
3074bff34e3Sthurlow 		return (0);
308613a2f6bSGordon Ross 
309613a2f6bSGordon Ross 	src = vmem;
3104bff34e3Sthurlow 	m = mbp->mb_cur;
3114bff34e3Sthurlow 	if ((error = m_getm(m, size, &m)) != 0)
3124bff34e3Sthurlow 		return (error);
3134bff34e3Sthurlow 	while (size > 0) {
3144bff34e3Sthurlow 		cplen = M_TRAILINGSPACE(m);
3154bff34e3Sthurlow 		if (cplen == 0) {
3164bff34e3Sthurlow 			m = m->m_next;
3174bff34e3Sthurlow 			continue;
3184bff34e3Sthurlow 		}
3194bff34e3Sthurlow 		if (cplen > size)
3204bff34e3Sthurlow 			cplen = size;
3214bff34e3Sthurlow 		dst = mtod(m, char *) + m->m_len;
322613a2f6bSGordon Ross 		if (src) {
323613a2f6bSGordon Ross 			bcopy(src, dst, cplen);
324613a2f6bSGordon Ross 			src += cplen;
3254bff34e3Sthurlow 		} else
3264bff34e3Sthurlow 			bzero(dst, cplen);
3274bff34e3Sthurlow 		size -= cplen;
3284bff34e3Sthurlow 		m->m_len += cplen;
3294bff34e3Sthurlow 		mbp->mb_count += cplen;
3304bff34e3Sthurlow 	}
3314bff34e3Sthurlow 	mbp->mb_pos = mtod(m, char *) + m->m_len;
3324bff34e3Sthurlow 	mbp->mb_cur = m;
3334bff34e3Sthurlow 	return (0);
3344bff34e3Sthurlow }
3354bff34e3Sthurlow 
336613a2f6bSGordon Ross /*
337613a2f6bSGordon Ross  * Append another mbuf to the mbuf chain.
338613a2f6bSGordon Ross  * If what we're appending is smaller than
339613a2f6bSGordon Ross  * the current trailing space, just copy.
340613a2f6bSGordon Ross  * This always consumes the passed mbuf.
341613a2f6bSGordon Ross  */
3424bff34e3Sthurlow int
343*02d09e03SGordon Ross mb_put_mbuf(mbchain_t *mbp, struct mbuf *m)
3444bff34e3Sthurlow {
345613a2f6bSGordon Ross 	struct mbuf *cm = mbp->mb_cur;
346613a2f6bSGordon Ross 	int ts = M_TRAILINGSPACE(cm);
347613a2f6bSGordon Ross 
348613a2f6bSGordon Ross 	if (m->m_next == NULL && m->m_len <= ts) {
349613a2f6bSGordon Ross 		/* just copy */
350*02d09e03SGordon Ross 		mb_put_mem(mbp, m->m_data, m->m_len, MB_MSYSTEM);
351613a2f6bSGordon Ross 		m_freem(m);
352613a2f6bSGordon Ross 		return (0);
353613a2f6bSGordon Ross 	}
354613a2f6bSGordon Ross 
355613a2f6bSGordon Ross 	cm->m_next = m;
3564bff34e3Sthurlow 	while (m) {
3574bff34e3Sthurlow 		mbp->mb_count += m->m_len;
3584bff34e3Sthurlow 		if (m->m_next == NULL)
3594bff34e3Sthurlow 			break;
3604bff34e3Sthurlow 		m = m->m_next;
3614bff34e3Sthurlow 	}
3624bff34e3Sthurlow 	mbp->mb_pos = mtod(m, char *) + m->m_len;
3634bff34e3Sthurlow 	mbp->mb_cur = m;
3644bff34e3Sthurlow 	return (0);
3654bff34e3Sthurlow }
3664bff34e3Sthurlow 
367613a2f6bSGordon Ross /*
368613a2f6bSGordon Ross  * Convenience function to put an OEM or Unicode string,
369613a2f6bSGordon Ross  * null terminated, and aligned if necessary.
370613a2f6bSGordon Ross  */
3714bff34e3Sthurlow int
372*02d09e03SGordon Ross mb_put_string(mbchain_t *mbp, const char *s, int uc)
3734bff34e3Sthurlow {
374613a2f6bSGordon Ross 	int err;
3754bff34e3Sthurlow 
376613a2f6bSGordon Ross 	if (uc) {
377613a2f6bSGordon Ross 		/* Put Unicode.  align(2) first. */
378613a2f6bSGordon Ross 		if (mbp->mb_count & 1)
379613a2f6bSGordon Ross 			mb_put_uint8(mbp, 0);
380613a2f6bSGordon Ross 		err = mb_put_ustring(mbp, s);
381613a2f6bSGordon Ross 	} else {
382613a2f6bSGordon Ross 		/* Put ASCII (really OEM) */
383613a2f6bSGordon Ross 		err = mb_put_astring(mbp, s);
3844bff34e3Sthurlow 	}
385613a2f6bSGordon Ross 
386613a2f6bSGordon Ross 	return (err);
387613a2f6bSGordon Ross }
388613a2f6bSGordon Ross 
389613a2f6bSGordon Ross /*
390613a2f6bSGordon Ross  * Put an ASCII string (really OEM), given a UTF-8 string.
391613a2f6bSGordon Ross  */
392613a2f6bSGordon Ross int
393*02d09e03SGordon Ross mb_put_astring(mbchain_t *mbp, const char *s)
394613a2f6bSGordon Ross {
395613a2f6bSGordon Ross 	char *abuf;
396613a2f6bSGordon Ross 	int err, len;
397613a2f6bSGordon Ross 
398613a2f6bSGordon Ross 	abuf = convert_utf8_to_wincs(s);
399613a2f6bSGordon Ross 	if (abuf == NULL)
400613a2f6bSGordon Ross 		return (ENOMEM);
401613a2f6bSGordon Ross 	len = strlen(abuf) + 1;
402*02d09e03SGordon Ross 	err = mb_put_mem(mbp, abuf, len, MB_MSYSTEM);
403613a2f6bSGordon Ross 	free(abuf);
404613a2f6bSGordon Ross 	return (err);
405613a2f6bSGordon Ross }
406613a2f6bSGordon Ross 
407613a2f6bSGordon Ross /*
408613a2f6bSGordon Ross  * Put UCS-2LE, given a UTF-8 string.
409613a2f6bSGordon Ross  */
410613a2f6bSGordon Ross int
411*02d09e03SGordon Ross mb_put_ustring(mbchain_t *mbp, const char *s)
412613a2f6bSGordon Ross {
413613a2f6bSGordon Ross 	uint16_t *ubuf;
414613a2f6bSGordon Ross 	int err, len;
415613a2f6bSGordon Ross 
416613a2f6bSGordon Ross 	ubuf = convert_utf8_to_leunicode(s);
417613a2f6bSGordon Ross 	if (ubuf == NULL)
418613a2f6bSGordon Ross 		return (ENOMEM);
419*02d09e03SGordon Ross 	len = 2 * (unicode_strlen(ubuf) + 1);
420*02d09e03SGordon Ross 	err = mb_put_mem(mbp, ubuf, len, MB_MSYSTEM);
421613a2f6bSGordon Ross 	free(ubuf);
422613a2f6bSGordon Ross 	return (err);
4234bff34e3Sthurlow }
4244bff34e3Sthurlow 
4254bff34e3Sthurlow /*
4264bff34e3Sthurlow  * Routines for fetching data from an mbuf chain
4274bff34e3Sthurlow  */
4284bff34e3Sthurlow #define	mb_left(m, p)	(mtod(m, char *) + (m)->m_len - (p))
4294bff34e3Sthurlow 
4304bff34e3Sthurlow int
431*02d09e03SGordon Ross md_get_uint8(mdchain_t *mbp, uint8_t *x)
4324bff34e3Sthurlow {
433*02d09e03SGordon Ross 	return (md_get_mem(mbp, x, 1, MB_MINLINE));
4344bff34e3Sthurlow }
4354bff34e3Sthurlow 
4364bff34e3Sthurlow int
437*02d09e03SGordon Ross md_get_uint16le(mdchain_t *mbp, uint16_t *x)
4384bff34e3Sthurlow {
4394bff34e3Sthurlow 	uint16_t v;
440613a2f6bSGordon Ross 	int err;
4414bff34e3Sthurlow 
442*02d09e03SGordon Ross 	if ((err = md_get_mem(mbp, &v, sizeof (v), MB_MINLINE)) != 0)
443613a2f6bSGordon Ross 		return (err);
4444bff34e3Sthurlow 	if (x != NULL)
4454bff34e3Sthurlow 		*x = letohs(v);
446613a2f6bSGordon Ross 	return (0);
4474bff34e3Sthurlow }
4484bff34e3Sthurlow 
4494bff34e3Sthurlow int
450*02d09e03SGordon Ross md_get_uint16be(mdchain_t *mbp, uint16_t *x) {
4514bff34e3Sthurlow 	uint16_t v;
452613a2f6bSGordon Ross 	int err;
4534bff34e3Sthurlow 
454*02d09e03SGordon Ross 	if ((err = md_get_mem(mbp, &v, sizeof (v), MB_MINLINE)) != 0)
455613a2f6bSGordon Ross 		return (err);
4564bff34e3Sthurlow 	if (x != NULL)
4574bff34e3Sthurlow 		*x = betohs(v);
458613a2f6bSGordon Ross 	return (0);
4594bff34e3Sthurlow }
4604bff34e3Sthurlow 
4614bff34e3Sthurlow int
462*02d09e03SGordon Ross md_get_uint32be(mdchain_t *mbp, uint32_t *x)
4634bff34e3Sthurlow {
4644bff34e3Sthurlow 	uint32_t v;
465613a2f6bSGordon Ross 	int err;
4664bff34e3Sthurlow 
467*02d09e03SGordon Ross 	if ((err = md_get_mem(mbp, &v, sizeof (v), MB_MINLINE)) != 0)
468613a2f6bSGordon Ross 		return (err);
4694bff34e3Sthurlow 	if (x != NULL)
4704bff34e3Sthurlow 		*x = betohl(v);
471613a2f6bSGordon Ross 	return (0);
4724bff34e3Sthurlow }
4734bff34e3Sthurlow 
4744bff34e3Sthurlow int
475*02d09e03SGordon Ross md_get_uint32le(mdchain_t *mbp, uint32_t *x)
4764bff34e3Sthurlow {
4774bff34e3Sthurlow 	uint32_t v;
478613a2f6bSGordon Ross 	int err;
4794bff34e3Sthurlow 
480*02d09e03SGordon Ross 	if ((err = md_get_mem(mbp, &v, sizeof (v), MB_MINLINE)) != 0)
481613a2f6bSGordon Ross 		return (err);
4824bff34e3Sthurlow 	if (x != NULL)
4834bff34e3Sthurlow 		*x = letohl(v);
484613a2f6bSGordon Ross 	return (0);
4854bff34e3Sthurlow }
4864bff34e3Sthurlow 
4874bff34e3Sthurlow int
488*02d09e03SGordon Ross md_get_uint64be(mdchain_t *mbp, uint64_t *x)
4894bff34e3Sthurlow {
4904bff34e3Sthurlow 	uint64_t v;
491613a2f6bSGordon Ross 	int err;
4924bff34e3Sthurlow 
493*02d09e03SGordon Ross 	if ((err = md_get_mem(mbp, &v, sizeof (v), MB_MINLINE)) != 0)
494613a2f6bSGordon Ross 		return (err);
4954bff34e3Sthurlow 	if (x != NULL)
4964bff34e3Sthurlow 		*x = betohq(v);
497613a2f6bSGordon Ross 	return (0);
4984bff34e3Sthurlow }
4994bff34e3Sthurlow 
5004bff34e3Sthurlow int
501*02d09e03SGordon Ross md_get_uint64le(mdchain_t *mbp, uint64_t *x)
5024bff34e3Sthurlow {
5034bff34e3Sthurlow 	uint64_t v;
504613a2f6bSGordon Ross 	int err;
5054bff34e3Sthurlow 
506*02d09e03SGordon Ross 	if ((err = md_get_mem(mbp, &v, sizeof (v), MB_MINLINE)) != 0)
507613a2f6bSGordon Ross 		return (err);
5084bff34e3Sthurlow 	if (x != NULL)
5094bff34e3Sthurlow 		*x = letohq(v);
510613a2f6bSGordon Ross 	return (0);
5114bff34e3Sthurlow }
5124bff34e3Sthurlow 
513*02d09e03SGordon Ross /* ARGSUSED */
5144bff34e3Sthurlow int
515*02d09e03SGordon Ross md_get_mem(mdchain_t *mbp, void *vmem, int size, int type)
5164bff34e3Sthurlow {
5174bff34e3Sthurlow 	struct mbuf *m = mbp->mb_cur;
518613a2f6bSGordon Ross 	char *dst = vmem;
5194bff34e3Sthurlow 	uint_t count;
5204bff34e3Sthurlow 
5214bff34e3Sthurlow 	while (size > 0) {
5224bff34e3Sthurlow 		if (m == NULL) {
523613a2f6bSGordon Ross 			/* DPRINT("incomplete copy"); */
5244bff34e3Sthurlow 			return (EBADRPC);
5254bff34e3Sthurlow 		}
5264bff34e3Sthurlow 		count = mb_left(m, mbp->mb_pos);
5274bff34e3Sthurlow 		if (count == 0) {
5284bff34e3Sthurlow 			mbp->mb_cur = m = m->m_next;
5294bff34e3Sthurlow 			if (m)
5304bff34e3Sthurlow 				mbp->mb_pos = mtod(m, char *);
5314bff34e3Sthurlow 			continue;
5324bff34e3Sthurlow 		}
5334bff34e3Sthurlow 		if (count > size)
5344bff34e3Sthurlow 			count = size;
5354bff34e3Sthurlow 		size -= count;
536613a2f6bSGordon Ross 		if (dst) {
5374bff34e3Sthurlow 			if (count == 1) {
538613a2f6bSGordon Ross 				*dst++ = *mbp->mb_pos;
5394bff34e3Sthurlow 			} else {
540613a2f6bSGordon Ross 				bcopy(mbp->mb_pos, dst, count);
541613a2f6bSGordon Ross 				dst += count;
5424bff34e3Sthurlow 			}
5434bff34e3Sthurlow 		}
5444bff34e3Sthurlow 		mbp->mb_pos += count;
5454bff34e3Sthurlow 	}
5464bff34e3Sthurlow 	return (0);
5474bff34e3Sthurlow }
548613a2f6bSGordon Ross 
549613a2f6bSGordon Ross /*
550613a2f6bSGordon Ross  * Get the next SIZE bytes as a separate mblk.
551613a2f6bSGordon Ross  * Nothing fancy here - just copy.
552613a2f6bSGordon Ross  */
553613a2f6bSGordon Ross int
554*02d09e03SGordon Ross md_get_mbuf(mdchain_t *mbp, int size, mbuf_t **ret)
555613a2f6bSGordon Ross {
556613a2f6bSGordon Ross 	mbuf_t *m;
557613a2f6bSGordon Ross 	int err;
558613a2f6bSGordon Ross 
559613a2f6bSGordon Ross 	err = m_get(size, &m);
560613a2f6bSGordon Ross 	if (err)
561613a2f6bSGordon Ross 		return (err);
562613a2f6bSGordon Ross 
563*02d09e03SGordon Ross 	err = md_get_mem(mbp, m->m_data, size, MB_MSYSTEM);
564613a2f6bSGordon Ross 	if (err) {
565613a2f6bSGordon Ross 		m_freem(m);
566613a2f6bSGordon Ross 		return (err);
567613a2f6bSGordon Ross 	}
568613a2f6bSGordon Ross 	m->m_len = size;
569613a2f6bSGordon Ross 	*ret = m;
570613a2f6bSGordon Ross 
571613a2f6bSGordon Ross 	return (0);
572613a2f6bSGordon Ross }
573613a2f6bSGordon Ross 
574613a2f6bSGordon Ross /*
575613a2f6bSGordon Ross  * Get a string from the mbuf chain,
576613a2f6bSGordon Ross  * either Unicode or OEM chars.
577613a2f6bSGordon Ross  */
578613a2f6bSGordon Ross int
579*02d09e03SGordon Ross md_get_string(mdchain_t *mbp, char **str_pp, int uc)
580613a2f6bSGordon Ross {
581613a2f6bSGordon Ross 	int err;
582613a2f6bSGordon Ross 
583613a2f6bSGordon Ross 	if (uc)
584*02d09e03SGordon Ross 		err = md_get_ustring(mbp, str_pp);
585613a2f6bSGordon Ross 	else
586*02d09e03SGordon Ross 		err = md_get_astring(mbp, str_pp);
587613a2f6bSGordon Ross 	return (err);
588613a2f6bSGordon Ross }
589613a2f6bSGordon Ross 
590613a2f6bSGordon Ross /*
591613a2f6bSGordon Ross  * Get an ASCII (really OEM) string from the mbuf chain
592613a2f6bSGordon Ross  * and convert it to UTF-8
593*02d09e03SGordon Ross  *
594*02d09e03SGordon Ross  * Similar to md_get_ustring below.
595613a2f6bSGordon Ross  */
596613a2f6bSGordon Ross int
597*02d09e03SGordon Ross md_get_astring(mdchain_t *real_mbp, char **str_pp)
598613a2f6bSGordon Ross {
599*02d09e03SGordon Ross 	mdchain_t tmp_mb, *mbp;
600613a2f6bSGordon Ross 	char *tstr, *ostr;
601613a2f6bSGordon Ross 	int err, i, slen;
602613a2f6bSGordon Ross 	uint8_t ch;
603613a2f6bSGordon Ross 
604613a2f6bSGordon Ross 	/*
605613a2f6bSGordon Ross 	 * First, figure out the string length.
606613a2f6bSGordon Ross 	 * Use a copy of the real_mbp so we don't
607613a2f6bSGordon Ross 	 * actually consume it here, then search for
608613a2f6bSGordon Ross 	 * the null (or end of data).
609613a2f6bSGordon Ross 	 */
610613a2f6bSGordon Ross 	bcopy(real_mbp, &tmp_mb, sizeof (tmp_mb));
611613a2f6bSGordon Ross 	mbp = &tmp_mb;
612613a2f6bSGordon Ross 	slen = 0;
613613a2f6bSGordon Ross 	for (;;) {
614*02d09e03SGordon Ross 		err = md_get_uint8(mbp, &ch);
615613a2f6bSGordon Ross 		if (err)
616613a2f6bSGordon Ross 			break;
617613a2f6bSGordon Ross 		if (ch == 0)
618613a2f6bSGordon Ross 			break;
619613a2f6bSGordon Ross 		slen++;
620613a2f6bSGordon Ross 	}
621613a2f6bSGordon Ross 
622613a2f6bSGordon Ross 	/*
623613a2f6bSGordon Ross 	 * Now read the (OEM) string for real.
624613a2f6bSGordon Ross 	 * No need to re-check errors.
625613a2f6bSGordon Ross 	 */
626613a2f6bSGordon Ross 	tstr = malloc(slen + 1);
627613a2f6bSGordon Ross 	if (tstr == NULL)
628613a2f6bSGordon Ross 		return (ENOMEM);
629613a2f6bSGordon Ross 	mbp = real_mbp;
630613a2f6bSGordon Ross 	for (i = 0; i < slen; i++) {
631*02d09e03SGordon Ross 		md_get_uint8(mbp, &ch);
632613a2f6bSGordon Ross 		tstr[i] = ch;
633613a2f6bSGordon Ross 	}
634613a2f6bSGordon Ross 	tstr[i] = 0;
635*02d09e03SGordon Ross 	md_get_uint8(mbp, NULL);
636613a2f6bSGordon Ross 
637613a2f6bSGordon Ross 	/*
638613a2f6bSGordon Ross 	 * Convert OEM to UTF-8
639613a2f6bSGordon Ross 	 */
640613a2f6bSGordon Ross 	ostr = convert_wincs_to_utf8(tstr);
641613a2f6bSGordon Ross 	free(tstr);
642613a2f6bSGordon Ross 	if (ostr == NULL)
643613a2f6bSGordon Ross 		return (ENOMEM);
644613a2f6bSGordon Ross 
645613a2f6bSGordon Ross 	*str_pp = ostr;
646613a2f6bSGordon Ross 	return (0);
647613a2f6bSGordon Ross }
648613a2f6bSGordon Ross 
649613a2f6bSGordon Ross /*
650613a2f6bSGordon Ross  * Get a UCS-2LE string from the mbuf chain, and
651613a2f6bSGordon Ross  * convert it to UTF-8.
652613a2f6bSGordon Ross  *
653*02d09e03SGordon Ross  * Similar to md_get_astring above.
654613a2f6bSGordon Ross  */
655613a2f6bSGordon Ross int
656*02d09e03SGordon Ross md_get_ustring(mdchain_t *real_mbp, char **str_pp)
657613a2f6bSGordon Ross {
658*02d09e03SGordon Ross 	mdchain_t tmp_mb, *mbp;
659613a2f6bSGordon Ross 	uint16_t *tstr;
660613a2f6bSGordon Ross 	char *ostr;
661613a2f6bSGordon Ross 	int err, i, slen;
662613a2f6bSGordon Ross 	uint16_t ch;
663613a2f6bSGordon Ross 
664613a2f6bSGordon Ross 	/*
665613a2f6bSGordon Ross 	 * First, align(2) on the real_mbp
666613a2f6bSGordon Ross 	 */
667613a2f6bSGordon Ross 	if (((uintptr_t)real_mbp->mb_pos) & 1)
668*02d09e03SGordon Ross 		md_get_uint8(real_mbp, NULL);
669613a2f6bSGordon Ross 
670613a2f6bSGordon Ross 	/*
671613a2f6bSGordon Ross 	 * Next, figure out the string length.
672613a2f6bSGordon Ross 	 * Use a copy of the real_mbp so we don't
673613a2f6bSGordon Ross 	 * actually consume it here, then search for
674613a2f6bSGordon Ross 	 * the null (or end of data).
675613a2f6bSGordon Ross 	 */
676613a2f6bSGordon Ross 	bcopy(real_mbp, &tmp_mb, sizeof (tmp_mb));
677613a2f6bSGordon Ross 	mbp = &tmp_mb;
678613a2f6bSGordon Ross 	slen = 0;
679613a2f6bSGordon Ross 	for (;;) {
680*02d09e03SGordon Ross 		err = md_get_uint16le(mbp, &ch);
681613a2f6bSGordon Ross 		if (err)
682613a2f6bSGordon Ross 			break;
683613a2f6bSGordon Ross 		if (ch == 0)
684613a2f6bSGordon Ross 			break;
685613a2f6bSGordon Ross 		slen++;
686613a2f6bSGordon Ross 	}
687613a2f6bSGordon Ross 
688613a2f6bSGordon Ross 	/*
689613a2f6bSGordon Ross 	 * Now read the (UCS-2) string for real.
690613a2f6bSGordon Ross 	 * No need to re-check errors.  Note:
691613a2f6bSGordon Ross 	 * This puts the UCS-2 in NATIVE order!
692613a2f6bSGordon Ross 	 */
693613a2f6bSGordon Ross 	tstr = calloc(slen + 1, 2);
694613a2f6bSGordon Ross 	if (tstr == NULL)
695613a2f6bSGordon Ross 		return (ENOMEM);
696613a2f6bSGordon Ross 	mbp = real_mbp;
697613a2f6bSGordon Ross 	for (i = 0; i < slen; i++) {
698*02d09e03SGordon Ross 		md_get_uint16le(mbp, &ch);
699613a2f6bSGordon Ross 		tstr[i] = ch;
700613a2f6bSGordon Ross 	}
701613a2f6bSGordon Ross 	tstr[i] = 0;
702*02d09e03SGordon Ross 	md_get_uint16le(mbp, NULL);
703613a2f6bSGordon Ross 
704613a2f6bSGordon Ross 	/*
705613a2f6bSGordon Ross 	 * Convert UCS-2 (native!) to UTF-8
706613a2f6bSGordon Ross 	 */
707613a2f6bSGordon Ross 	ostr = convert_unicode_to_utf8(tstr);
708613a2f6bSGordon Ross 	free(tstr);
709613a2f6bSGordon Ross 	if (ostr == NULL)
710613a2f6bSGordon Ross 		return (ENOMEM);
711613a2f6bSGordon Ross 
712613a2f6bSGordon Ross 	*str_pp = ostr;
713613a2f6bSGordon Ross 	return (0);
714613a2f6bSGordon Ross }
715