xref: /titanic_51/usr/src/lib/libsmbfs/smb/mbuf.c (revision 15359501f7d4b9abebd7b7bf6efd5982a8e7eb27)
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 /*
36*15359501SGordon Ross  * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
379c9af259SGordon Ross  */
384bff34e3Sthurlow 
394bff34e3Sthurlow #include <sys/types.h>
404bff34e3Sthurlow #include <ctype.h>
414bff34e3Sthurlow #include <errno.h>
424bff34e3Sthurlow #include <stdio.h>
434bff34e3Sthurlow #include <stdlib.h>
444bff34e3Sthurlow #include <string.h>
454bff34e3Sthurlow #include <strings.h>
464bff34e3Sthurlow #include <libintl.h>
477568150aSgwr #include <assert.h>
484bff34e3Sthurlow 
494bff34e3Sthurlow #include <netsmb/smb_lib.h>
504bff34e3Sthurlow #include <netsmb/mchain.h>
514bff34e3Sthurlow 
529c9af259SGordon Ross #include "private.h"
53613a2f6bSGordon Ross #include "charsets.h"
544bff34e3Sthurlow 
5502d09e03SGordon Ross /*
5602d09e03SGordon Ross  * Note: Leaving a little space (8 bytes) between the
5702d09e03SGordon Ross  * mbuf header and the start of the data so we can
5802d09e03SGordon Ross  * prepend a NetBIOS header in that space.
5902d09e03SGordon Ross  */
6002d09e03SGordon Ross #define	M_ALIGNFACTOR	(sizeof (long))
6102d09e03SGordon Ross #define	M_ALIGN(len)	(((len) + M_ALIGNFACTOR - 1) & ~(M_ALIGNFACTOR - 1))
6202d09e03SGordon Ross #define	M_BASESIZE	(sizeof (struct mbuf) + 8)
6302d09e03SGordon Ross #define	M_MINSIZE	(1024 - M_BASESIZE)
6402d09e03SGordon Ross #define	M_TOP(m)	((char *)(m) + M_BASESIZE)
6502d09e03SGordon Ross #define	M_TRAILINGSPACE(m) ((m)->m_maxlen - (m)->m_len)
6602d09e03SGordon Ross 
6702d09e03SGordon Ross int
6802d09e03SGordon Ross m_get(int len, struct mbuf **mpp)
694bff34e3Sthurlow {
704bff34e3Sthurlow 	struct mbuf *m;
714bff34e3Sthurlow 
727568150aSgwr 	assert(len < 0x100000); /* sanity */
737568150aSgwr 
744bff34e3Sthurlow 	len = M_ALIGN(len);
754bff34e3Sthurlow 	if (len < M_MINSIZE)
764bff34e3Sthurlow 		len = M_MINSIZE;
774bff34e3Sthurlow 	m = malloc(M_BASESIZE + len);
784bff34e3Sthurlow 	if (m == NULL)
794bff34e3Sthurlow 		return (ENOMEM);
804bff34e3Sthurlow 	bzero(m, M_BASESIZE + len);
814bff34e3Sthurlow 	m->m_maxlen = len;
824bff34e3Sthurlow 	m->m_data = M_TOP(m);
834bff34e3Sthurlow 	*mpp = m;
844bff34e3Sthurlow 	return (0);
854bff34e3Sthurlow }
864bff34e3Sthurlow 
874bff34e3Sthurlow static void
884bff34e3Sthurlow m_free(struct mbuf *m)
894bff34e3Sthurlow {
904bff34e3Sthurlow 	free(m);
914bff34e3Sthurlow }
924bff34e3Sthurlow 
93613a2f6bSGordon Ross void
944bff34e3Sthurlow m_freem(struct mbuf *m0)
954bff34e3Sthurlow {
964bff34e3Sthurlow 	struct mbuf *m;
974bff34e3Sthurlow 
984bff34e3Sthurlow 	while (m0) {
994bff34e3Sthurlow 		m = m0->m_next;
1004bff34e3Sthurlow 		m_free(m0);
1014bff34e3Sthurlow 		m0 = m;
1024bff34e3Sthurlow 	}
1034bff34e3Sthurlow }
1044bff34e3Sthurlow 
105613a2f6bSGordon Ross size_t
1064bff34e3Sthurlow m_totlen(struct mbuf *m0)
1074bff34e3Sthurlow {
1084bff34e3Sthurlow 	struct mbuf *m = m0;
1094bff34e3Sthurlow 	int len = 0;
1104bff34e3Sthurlow 
1114bff34e3Sthurlow 	while (m) {
1124bff34e3Sthurlow 		len += m->m_len;
1134bff34e3Sthurlow 		m = m->m_next;
1144bff34e3Sthurlow 	}
1154bff34e3Sthurlow 	return (len);
1164bff34e3Sthurlow }
1174bff34e3Sthurlow 
1184bff34e3Sthurlow int
1194bff34e3Sthurlow m_lineup(struct mbuf *m0, struct mbuf **mpp)
1204bff34e3Sthurlow {
1214bff34e3Sthurlow 	struct mbuf *nm, *m;
1224bff34e3Sthurlow 	char *dp;
123*15359501SGordon Ross 	size_t len, totlen;
1244bff34e3Sthurlow 	int error;
1254bff34e3Sthurlow 
1264bff34e3Sthurlow 	if (m0->m_next == NULL) {
1274bff34e3Sthurlow 		*mpp = m0;
1284bff34e3Sthurlow 		return (0);
1294bff34e3Sthurlow 	}
130*15359501SGordon Ross 	totlen = m_totlen(m0);
131*15359501SGordon Ross 	if ((error = m_get(totlen, &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 	}
142*15359501SGordon Ross 	nm->m_len = totlen;
1434bff34e3Sthurlow 	*mpp = nm;
1444bff34e3Sthurlow 	return (0);
1454bff34e3Sthurlow }
1464bff34e3Sthurlow 
1474bff34e3Sthurlow int
14802d09e03SGordon Ross mb_init(struct mbdata *mbp)
14902d09e03SGordon Ross {
15002d09e03SGordon Ross 	return (mb_init_sz(mbp, M_MINSIZE));
15102d09e03SGordon Ross }
15202d09e03SGordon Ross 
15302d09e03SGordon Ross int
15402d09e03SGordon Ross mb_init_sz(struct mbdata *mbp, int size)
1554bff34e3Sthurlow {
1564bff34e3Sthurlow 	struct mbuf *m;
1574bff34e3Sthurlow 	int error;
1584bff34e3Sthurlow 
1594bff34e3Sthurlow 	if ((error = m_get(size, &m)) != 0)
1604bff34e3Sthurlow 		return (error);
16102d09e03SGordon Ross 	mb_initm(mbp, m);
16202d09e03SGordon Ross 	return (0);
1634bff34e3Sthurlow }
1644bff34e3Sthurlow 
16502d09e03SGordon Ross void
1664bff34e3Sthurlow mb_initm(struct mbdata *mbp, struct mbuf *m)
1674bff34e3Sthurlow {
1684bff34e3Sthurlow 	bzero(mbp, sizeof (*mbp));
1694bff34e3Sthurlow 	mbp->mb_top = mbp->mb_cur = m;
1704bff34e3Sthurlow 	mbp->mb_pos = mtod(m, char *);
1714bff34e3Sthurlow }
1724bff34e3Sthurlow 
17302d09e03SGordon Ross void
1744bff34e3Sthurlow mb_done(struct mbdata *mbp)
1754bff34e3Sthurlow {
1764bff34e3Sthurlow 	if (mbp->mb_top) {
1774bff34e3Sthurlow 		m_freem(mbp->mb_top);
1784bff34e3Sthurlow 		mbp->mb_top = NULL;
1794bff34e3Sthurlow 	}
1804bff34e3Sthurlow }
1814bff34e3Sthurlow 
1824bff34e3Sthurlow int
18302d09e03SGordon Ross m_getm(struct mbuf *top, int len, struct mbuf **mpp)
1844bff34e3Sthurlow {
1854bff34e3Sthurlow 	struct mbuf *m, *mp;
1867568150aSgwr 	int  error, ts;
1874bff34e3Sthurlow 
1884bff34e3Sthurlow 	for (mp = top; ; mp = mp->m_next) {
1897568150aSgwr 		ts = M_TRAILINGSPACE(mp);
1907568150aSgwr 		if (len <= ts)
1917568150aSgwr 			goto out;
1927568150aSgwr 		len -= ts;
1934bff34e3Sthurlow 		if (mp->m_next == NULL)
1944bff34e3Sthurlow 			break;
1954bff34e3Sthurlow 
1964bff34e3Sthurlow 	}
1974bff34e3Sthurlow 	if (len > 0) {
1984bff34e3Sthurlow 		if ((error = m_get(len, &m)) != 0)
1994bff34e3Sthurlow 			return (error);
2004bff34e3Sthurlow 		mp->m_next = m;
2014bff34e3Sthurlow 	}
2027568150aSgwr out:
2034bff34e3Sthurlow 	*mpp = top;
2044bff34e3Sthurlow 	return (0);
2054bff34e3Sthurlow }
2064bff34e3Sthurlow 
2074bff34e3Sthurlow /*
2084bff34e3Sthurlow  * Routines to put data in a buffer
2094bff34e3Sthurlow  */
2104bff34e3Sthurlow 
21102d09e03SGordon Ross void *
21202d09e03SGordon Ross mb_reserve(mbchain_t *mbp, int size)
21302d09e03SGordon Ross {
21402d09e03SGordon Ross 	char *p;
21502d09e03SGordon Ross 
21602d09e03SGordon Ross 	if (mb_fit(mbp, size, &p) != 0)
21702d09e03SGordon Ross 		return (NULL);
21802d09e03SGordon Ross 
21902d09e03SGordon Ross 	return (p);
22002d09e03SGordon Ross }
22102d09e03SGordon Ross 
2224bff34e3Sthurlow /*
2234bff34e3Sthurlow  * Check if object of size 'size' fit to the current position and
2244bff34e3Sthurlow  * allocate new mbuf if not. Advance pointers and increase length of mbuf(s).
2254bff34e3Sthurlow  * Return pointer to the object placeholder or NULL if any error occured.
2264bff34e3Sthurlow  */
2274bff34e3Sthurlow int
22802d09e03SGordon Ross mb_fit(mbchain_t *mbp, int size, char **pp)
2294bff34e3Sthurlow {
2304bff34e3Sthurlow 	struct mbuf *m, *mn;
2314bff34e3Sthurlow 	int error;
2324bff34e3Sthurlow 
2334bff34e3Sthurlow 	m = mbp->mb_cur;
2344bff34e3Sthurlow 	if (M_TRAILINGSPACE(m) < (int)size) {
2354bff34e3Sthurlow 		if ((error = m_get(size, &mn)) != 0)
2364bff34e3Sthurlow 			return (error);
2374bff34e3Sthurlow 		mbp->mb_pos = mtod(mn, char *);
2384bff34e3Sthurlow 		mbp->mb_cur = m->m_next = mn;
2394bff34e3Sthurlow 		m = mn;
2404bff34e3Sthurlow 	}
2414bff34e3Sthurlow 	m->m_len += size;
2424bff34e3Sthurlow 	*pp = mbp->mb_pos;
2434bff34e3Sthurlow 	mbp->mb_pos += size;
2444bff34e3Sthurlow 	mbp->mb_count += size;
2454bff34e3Sthurlow 	return (0);
2464bff34e3Sthurlow }
2474bff34e3Sthurlow 
2484bff34e3Sthurlow int
24902d09e03SGordon Ross mb_put_uint8(mbchain_t *mbp, uint8_t x)
2504bff34e3Sthurlow {
2519c9af259SGordon Ross 	uint8_t y = x;
25202d09e03SGordon Ross 	return (mb_put_mem(mbp, &y, sizeof (y), MB_MINLINE));
2534bff34e3Sthurlow }
2544bff34e3Sthurlow 
2554bff34e3Sthurlow int
25602d09e03SGordon Ross mb_put_uint16be(mbchain_t *mbp, uint16_t x)
2574bff34e3Sthurlow {
2589c9af259SGordon Ross 	uint16_t y = htobes(x);
25902d09e03SGordon Ross 	return (mb_put_mem(mbp, &y, sizeof (y), MB_MINLINE));
2604bff34e3Sthurlow }
2614bff34e3Sthurlow 
2624bff34e3Sthurlow int
26302d09e03SGordon Ross mb_put_uint16le(mbchain_t *mbp, uint16_t x)
2644bff34e3Sthurlow {
2659c9af259SGordon Ross 	uint16_t y = htoles(x);
26602d09e03SGordon Ross 	return (mb_put_mem(mbp, &y, sizeof (y), MB_MINLINE));
2674bff34e3Sthurlow }
2684bff34e3Sthurlow 
2694bff34e3Sthurlow int
27002d09e03SGordon Ross mb_put_uint32be(mbchain_t *mbp, uint32_t x)
2714bff34e3Sthurlow {
2729c9af259SGordon Ross 	uint32_t y = htobel(x);
27302d09e03SGordon Ross 	return (mb_put_mem(mbp, &y, sizeof (y), MB_MINLINE));
2744bff34e3Sthurlow }
2754bff34e3Sthurlow 
2764bff34e3Sthurlow int
27702d09e03SGordon Ross mb_put_uint32le(mbchain_t *mbp, uint32_t x)
2784bff34e3Sthurlow {
2799c9af259SGordon Ross 	uint32_t y = htolel(x);
28002d09e03SGordon Ross 	return (mb_put_mem(mbp, &y, sizeof (y), MB_MINLINE));
2814bff34e3Sthurlow }
2824bff34e3Sthurlow 
2834bff34e3Sthurlow int
28402d09e03SGordon Ross mb_put_uint64be(mbchain_t *mbp, uint64_t x)
2854bff34e3Sthurlow {
2869c9af259SGordon Ross 	uint64_t y = htobeq(x);
28702d09e03SGordon Ross 	return (mb_put_mem(mbp, &y, sizeof (y), MB_MINLINE));
2884bff34e3Sthurlow }
2894bff34e3Sthurlow 
2904bff34e3Sthurlow int
29102d09e03SGordon Ross mb_put_uint64le(mbchain_t *mbp, uint64_t x)
2924bff34e3Sthurlow {
2939c9af259SGordon Ross 	uint64_t y = htoleq(x);
29402d09e03SGordon Ross 	return (mb_put_mem(mbp, &y, sizeof (y), MB_MINLINE));
2954bff34e3Sthurlow }
2964bff34e3Sthurlow 
29702d09e03SGordon Ross /* ARGSUSED */
2984bff34e3Sthurlow int
29902d09e03SGordon Ross mb_put_mem(mbchain_t *mbp, const void *vmem, int size, int type)
3004bff34e3Sthurlow {
3014bff34e3Sthurlow 	struct mbuf *m;
302613a2f6bSGordon Ross 	const char *src;
3034bff34e3Sthurlow 	char  *dst;
3044bff34e3Sthurlow 	size_t cplen;
3054bff34e3Sthurlow 	int error;
3064bff34e3Sthurlow 
3074bff34e3Sthurlow 	if (size == 0)
3084bff34e3Sthurlow 		return (0);
309613a2f6bSGordon Ross 
310613a2f6bSGordon Ross 	src = vmem;
3114bff34e3Sthurlow 	m = mbp->mb_cur;
3124bff34e3Sthurlow 	if ((error = m_getm(m, size, &m)) != 0)
3134bff34e3Sthurlow 		return (error);
3144bff34e3Sthurlow 	while (size > 0) {
3154bff34e3Sthurlow 		cplen = M_TRAILINGSPACE(m);
3164bff34e3Sthurlow 		if (cplen == 0) {
3174bff34e3Sthurlow 			m = m->m_next;
3184bff34e3Sthurlow 			continue;
3194bff34e3Sthurlow 		}
3204bff34e3Sthurlow 		if (cplen > size)
3214bff34e3Sthurlow 			cplen = size;
3224bff34e3Sthurlow 		dst = mtod(m, char *) + m->m_len;
323613a2f6bSGordon Ross 		if (src) {
324613a2f6bSGordon Ross 			bcopy(src, dst, cplen);
325613a2f6bSGordon Ross 			src += cplen;
3264bff34e3Sthurlow 		} else
3274bff34e3Sthurlow 			bzero(dst, cplen);
3284bff34e3Sthurlow 		size -= cplen;
3294bff34e3Sthurlow 		m->m_len += cplen;
3304bff34e3Sthurlow 		mbp->mb_count += cplen;
3314bff34e3Sthurlow 	}
3324bff34e3Sthurlow 	mbp->mb_pos = mtod(m, char *) + m->m_len;
3334bff34e3Sthurlow 	mbp->mb_cur = m;
3344bff34e3Sthurlow 	return (0);
3354bff34e3Sthurlow }
3364bff34e3Sthurlow 
337613a2f6bSGordon Ross /*
338613a2f6bSGordon Ross  * Append another mbuf to the mbuf chain.
339613a2f6bSGordon Ross  * If what we're appending is smaller than
340613a2f6bSGordon Ross  * the current trailing space, just copy.
341613a2f6bSGordon Ross  * This always consumes the passed mbuf.
342613a2f6bSGordon Ross  */
3434bff34e3Sthurlow int
34402d09e03SGordon Ross mb_put_mbuf(mbchain_t *mbp, struct mbuf *m)
3454bff34e3Sthurlow {
346613a2f6bSGordon Ross 	struct mbuf *cm = mbp->mb_cur;
347613a2f6bSGordon Ross 	int ts = M_TRAILINGSPACE(cm);
348613a2f6bSGordon Ross 
349613a2f6bSGordon Ross 	if (m->m_next == NULL && m->m_len <= ts) {
350613a2f6bSGordon Ross 		/* just copy */
35102d09e03SGordon Ross 		mb_put_mem(mbp, m->m_data, m->m_len, MB_MSYSTEM);
352613a2f6bSGordon Ross 		m_freem(m);
353613a2f6bSGordon Ross 		return (0);
354613a2f6bSGordon Ross 	}
355613a2f6bSGordon Ross 
356613a2f6bSGordon Ross 	cm->m_next = m;
3574bff34e3Sthurlow 	while (m) {
3584bff34e3Sthurlow 		mbp->mb_count += m->m_len;
3594bff34e3Sthurlow 		if (m->m_next == NULL)
3604bff34e3Sthurlow 			break;
3614bff34e3Sthurlow 		m = m->m_next;
3624bff34e3Sthurlow 	}
3634bff34e3Sthurlow 	mbp->mb_pos = mtod(m, char *) + m->m_len;
3644bff34e3Sthurlow 	mbp->mb_cur = m;
3654bff34e3Sthurlow 	return (0);
3664bff34e3Sthurlow }
3674bff34e3Sthurlow 
368613a2f6bSGordon Ross /*
369613a2f6bSGordon Ross  * Convenience function to put an OEM or Unicode string,
370613a2f6bSGordon Ross  * null terminated, and aligned if necessary.
371613a2f6bSGordon Ross  */
3724bff34e3Sthurlow int
37302d09e03SGordon Ross mb_put_string(mbchain_t *mbp, const char *s, int uc)
3744bff34e3Sthurlow {
375613a2f6bSGordon Ross 	int err;
3764bff34e3Sthurlow 
377613a2f6bSGordon Ross 	if (uc) {
378613a2f6bSGordon Ross 		/* Put Unicode.  align(2) first. */
379613a2f6bSGordon Ross 		if (mbp->mb_count & 1)
380613a2f6bSGordon Ross 			mb_put_uint8(mbp, 0);
381613a2f6bSGordon Ross 		err = mb_put_ustring(mbp, s);
382613a2f6bSGordon Ross 	} else {
383613a2f6bSGordon Ross 		/* Put ASCII (really OEM) */
384613a2f6bSGordon Ross 		err = mb_put_astring(mbp, s);
3854bff34e3Sthurlow 	}
386613a2f6bSGordon Ross 
387613a2f6bSGordon Ross 	return (err);
388613a2f6bSGordon Ross }
389613a2f6bSGordon Ross 
390613a2f6bSGordon Ross /*
391613a2f6bSGordon Ross  * Put an ASCII string (really OEM), given a UTF-8 string.
392613a2f6bSGordon Ross  */
393613a2f6bSGordon Ross int
39402d09e03SGordon Ross mb_put_astring(mbchain_t *mbp, const char *s)
395613a2f6bSGordon Ross {
396613a2f6bSGordon Ross 	char *abuf;
397613a2f6bSGordon Ross 	int err, len;
398613a2f6bSGordon Ross 
399613a2f6bSGordon Ross 	abuf = convert_utf8_to_wincs(s);
400613a2f6bSGordon Ross 	if (abuf == NULL)
401613a2f6bSGordon Ross 		return (ENOMEM);
402613a2f6bSGordon Ross 	len = strlen(abuf) + 1;
40302d09e03SGordon Ross 	err = mb_put_mem(mbp, abuf, len, MB_MSYSTEM);
404613a2f6bSGordon Ross 	free(abuf);
405613a2f6bSGordon Ross 	return (err);
406613a2f6bSGordon Ross }
407613a2f6bSGordon Ross 
408613a2f6bSGordon Ross /*
409613a2f6bSGordon Ross  * Put UCS-2LE, given a UTF-8 string.
410613a2f6bSGordon Ross  */
411613a2f6bSGordon Ross int
41202d09e03SGordon Ross mb_put_ustring(mbchain_t *mbp, const char *s)
413613a2f6bSGordon Ross {
414613a2f6bSGordon Ross 	uint16_t *ubuf;
415613a2f6bSGordon Ross 	int err, len;
416613a2f6bSGordon Ross 
417613a2f6bSGordon Ross 	ubuf = convert_utf8_to_leunicode(s);
418613a2f6bSGordon Ross 	if (ubuf == NULL)
419613a2f6bSGordon Ross 		return (ENOMEM);
42002d09e03SGordon Ross 	len = 2 * (unicode_strlen(ubuf) + 1);
42102d09e03SGordon Ross 	err = mb_put_mem(mbp, ubuf, len, MB_MSYSTEM);
422613a2f6bSGordon Ross 	free(ubuf);
423613a2f6bSGordon Ross 	return (err);
4244bff34e3Sthurlow }
4254bff34e3Sthurlow 
4264bff34e3Sthurlow /*
4274bff34e3Sthurlow  * Routines for fetching data from an mbuf chain
4284bff34e3Sthurlow  */
4294bff34e3Sthurlow #define	mb_left(m, p)	(mtod(m, char *) + (m)->m_len - (p))
4304bff34e3Sthurlow 
4314bff34e3Sthurlow int
43202d09e03SGordon Ross md_get_uint8(mdchain_t *mbp, uint8_t *x)
4334bff34e3Sthurlow {
43402d09e03SGordon Ross 	return (md_get_mem(mbp, x, 1, MB_MINLINE));
4354bff34e3Sthurlow }
4364bff34e3Sthurlow 
4374bff34e3Sthurlow int
43802d09e03SGordon Ross md_get_uint16le(mdchain_t *mbp, uint16_t *x)
4394bff34e3Sthurlow {
4404bff34e3Sthurlow 	uint16_t v;
441613a2f6bSGordon Ross 	int err;
4424bff34e3Sthurlow 
44302d09e03SGordon Ross 	if ((err = md_get_mem(mbp, &v, sizeof (v), MB_MINLINE)) != 0)
444613a2f6bSGordon Ross 		return (err);
4454bff34e3Sthurlow 	if (x != NULL)
4464bff34e3Sthurlow 		*x = letohs(v);
447613a2f6bSGordon Ross 	return (0);
4484bff34e3Sthurlow }
4494bff34e3Sthurlow 
4504bff34e3Sthurlow int
45102d09e03SGordon Ross md_get_uint16be(mdchain_t *mbp, uint16_t *x) {
4524bff34e3Sthurlow 	uint16_t v;
453613a2f6bSGordon Ross 	int err;
4544bff34e3Sthurlow 
45502d09e03SGordon Ross 	if ((err = md_get_mem(mbp, &v, sizeof (v), MB_MINLINE)) != 0)
456613a2f6bSGordon Ross 		return (err);
4574bff34e3Sthurlow 	if (x != NULL)
4584bff34e3Sthurlow 		*x = betohs(v);
459613a2f6bSGordon Ross 	return (0);
4604bff34e3Sthurlow }
4614bff34e3Sthurlow 
4624bff34e3Sthurlow int
46302d09e03SGordon Ross md_get_uint32be(mdchain_t *mbp, uint32_t *x)
4644bff34e3Sthurlow {
4654bff34e3Sthurlow 	uint32_t v;
466613a2f6bSGordon Ross 	int err;
4674bff34e3Sthurlow 
46802d09e03SGordon Ross 	if ((err = md_get_mem(mbp, &v, sizeof (v), MB_MINLINE)) != 0)
469613a2f6bSGordon Ross 		return (err);
4704bff34e3Sthurlow 	if (x != NULL)
4714bff34e3Sthurlow 		*x = betohl(v);
472613a2f6bSGordon Ross 	return (0);
4734bff34e3Sthurlow }
4744bff34e3Sthurlow 
4754bff34e3Sthurlow int
47602d09e03SGordon Ross md_get_uint32le(mdchain_t *mbp, uint32_t *x)
4774bff34e3Sthurlow {
4784bff34e3Sthurlow 	uint32_t v;
479613a2f6bSGordon Ross 	int err;
4804bff34e3Sthurlow 
48102d09e03SGordon Ross 	if ((err = md_get_mem(mbp, &v, sizeof (v), MB_MINLINE)) != 0)
482613a2f6bSGordon Ross 		return (err);
4834bff34e3Sthurlow 	if (x != NULL)
4844bff34e3Sthurlow 		*x = letohl(v);
485613a2f6bSGordon Ross 	return (0);
4864bff34e3Sthurlow }
4874bff34e3Sthurlow 
4884bff34e3Sthurlow int
48902d09e03SGordon Ross md_get_uint64be(mdchain_t *mbp, uint64_t *x)
4904bff34e3Sthurlow {
4914bff34e3Sthurlow 	uint64_t v;
492613a2f6bSGordon Ross 	int err;
4934bff34e3Sthurlow 
49402d09e03SGordon Ross 	if ((err = md_get_mem(mbp, &v, sizeof (v), MB_MINLINE)) != 0)
495613a2f6bSGordon Ross 		return (err);
4964bff34e3Sthurlow 	if (x != NULL)
4974bff34e3Sthurlow 		*x = betohq(v);
498613a2f6bSGordon Ross 	return (0);
4994bff34e3Sthurlow }
5004bff34e3Sthurlow 
5014bff34e3Sthurlow int
50202d09e03SGordon Ross md_get_uint64le(mdchain_t *mbp, uint64_t *x)
5034bff34e3Sthurlow {
5044bff34e3Sthurlow 	uint64_t v;
505613a2f6bSGordon Ross 	int err;
5064bff34e3Sthurlow 
50702d09e03SGordon Ross 	if ((err = md_get_mem(mbp, &v, sizeof (v), MB_MINLINE)) != 0)
508613a2f6bSGordon Ross 		return (err);
5094bff34e3Sthurlow 	if (x != NULL)
5104bff34e3Sthurlow 		*x = letohq(v);
511613a2f6bSGordon Ross 	return (0);
5124bff34e3Sthurlow }
5134bff34e3Sthurlow 
51402d09e03SGordon Ross /* ARGSUSED */
5154bff34e3Sthurlow int
51602d09e03SGordon Ross md_get_mem(mdchain_t *mbp, void *vmem, int size, int type)
5174bff34e3Sthurlow {
5184bff34e3Sthurlow 	struct mbuf *m = mbp->mb_cur;
519613a2f6bSGordon Ross 	char *dst = vmem;
5204bff34e3Sthurlow 	uint_t count;
5214bff34e3Sthurlow 
5224bff34e3Sthurlow 	while (size > 0) {
5234bff34e3Sthurlow 		if (m == NULL) {
524613a2f6bSGordon Ross 			/* DPRINT("incomplete copy"); */
5254bff34e3Sthurlow 			return (EBADRPC);
5264bff34e3Sthurlow 		}
5274bff34e3Sthurlow 		count = mb_left(m, mbp->mb_pos);
5284bff34e3Sthurlow 		if (count == 0) {
5294bff34e3Sthurlow 			mbp->mb_cur = m = m->m_next;
5304bff34e3Sthurlow 			if (m)
5314bff34e3Sthurlow 				mbp->mb_pos = mtod(m, char *);
5324bff34e3Sthurlow 			continue;
5334bff34e3Sthurlow 		}
5344bff34e3Sthurlow 		if (count > size)
5354bff34e3Sthurlow 			count = size;
5364bff34e3Sthurlow 		size -= count;
537613a2f6bSGordon Ross 		if (dst) {
5384bff34e3Sthurlow 			if (count == 1) {
539613a2f6bSGordon Ross 				*dst++ = *mbp->mb_pos;
5404bff34e3Sthurlow 			} else {
541613a2f6bSGordon Ross 				bcopy(mbp->mb_pos, dst, count);
542613a2f6bSGordon Ross 				dst += count;
5434bff34e3Sthurlow 			}
5444bff34e3Sthurlow 		}
5454bff34e3Sthurlow 		mbp->mb_pos += count;
5464bff34e3Sthurlow 	}
5474bff34e3Sthurlow 	return (0);
5484bff34e3Sthurlow }
549613a2f6bSGordon Ross 
550613a2f6bSGordon Ross /*
551613a2f6bSGordon Ross  * Get the next SIZE bytes as a separate mblk.
552613a2f6bSGordon Ross  * Nothing fancy here - just copy.
553613a2f6bSGordon Ross  */
554613a2f6bSGordon Ross int
55502d09e03SGordon Ross md_get_mbuf(mdchain_t *mbp, int size, mbuf_t **ret)
556613a2f6bSGordon Ross {
557613a2f6bSGordon Ross 	mbuf_t *m;
558613a2f6bSGordon Ross 	int err;
559613a2f6bSGordon Ross 
560613a2f6bSGordon Ross 	err = m_get(size, &m);
561613a2f6bSGordon Ross 	if (err)
562613a2f6bSGordon Ross 		return (err);
563613a2f6bSGordon Ross 
56402d09e03SGordon Ross 	err = md_get_mem(mbp, m->m_data, size, MB_MSYSTEM);
565613a2f6bSGordon Ross 	if (err) {
566613a2f6bSGordon Ross 		m_freem(m);
567613a2f6bSGordon Ross 		return (err);
568613a2f6bSGordon Ross 	}
569613a2f6bSGordon Ross 	m->m_len = size;
570613a2f6bSGordon Ross 	*ret = m;
571613a2f6bSGordon Ross 
572613a2f6bSGordon Ross 	return (0);
573613a2f6bSGordon Ross }
574613a2f6bSGordon Ross 
575613a2f6bSGordon Ross /*
576613a2f6bSGordon Ross  * Get a string from the mbuf chain,
577613a2f6bSGordon Ross  * either Unicode or OEM chars.
578613a2f6bSGordon Ross  */
579613a2f6bSGordon Ross int
58002d09e03SGordon Ross md_get_string(mdchain_t *mbp, char **str_pp, int uc)
581613a2f6bSGordon Ross {
582613a2f6bSGordon Ross 	int err;
583613a2f6bSGordon Ross 
584613a2f6bSGordon Ross 	if (uc)
58502d09e03SGordon Ross 		err = md_get_ustring(mbp, str_pp);
586613a2f6bSGordon Ross 	else
58702d09e03SGordon Ross 		err = md_get_astring(mbp, str_pp);
588613a2f6bSGordon Ross 	return (err);
589613a2f6bSGordon Ross }
590613a2f6bSGordon Ross 
591613a2f6bSGordon Ross /*
592613a2f6bSGordon Ross  * Get an ASCII (really OEM) string from the mbuf chain
593613a2f6bSGordon Ross  * and convert it to UTF-8
59402d09e03SGordon Ross  *
59502d09e03SGordon Ross  * Similar to md_get_ustring below.
596613a2f6bSGordon Ross  */
597613a2f6bSGordon Ross int
59802d09e03SGordon Ross md_get_astring(mdchain_t *real_mbp, char **str_pp)
599613a2f6bSGordon Ross {
60002d09e03SGordon Ross 	mdchain_t tmp_mb, *mbp;
601613a2f6bSGordon Ross 	char *tstr, *ostr;
602613a2f6bSGordon Ross 	int err, i, slen;
603613a2f6bSGordon Ross 	uint8_t ch;
604613a2f6bSGordon Ross 
605613a2f6bSGordon Ross 	/*
606613a2f6bSGordon Ross 	 * First, figure out the string length.
607613a2f6bSGordon Ross 	 * Use a copy of the real_mbp so we don't
608613a2f6bSGordon Ross 	 * actually consume it here, then search for
609613a2f6bSGordon Ross 	 * the null (or end of data).
610613a2f6bSGordon Ross 	 */
611613a2f6bSGordon Ross 	bcopy(real_mbp, &tmp_mb, sizeof (tmp_mb));
612613a2f6bSGordon Ross 	mbp = &tmp_mb;
613613a2f6bSGordon Ross 	slen = 0;
614613a2f6bSGordon Ross 	for (;;) {
61502d09e03SGordon Ross 		err = md_get_uint8(mbp, &ch);
616613a2f6bSGordon Ross 		if (err)
617613a2f6bSGordon Ross 			break;
618613a2f6bSGordon Ross 		if (ch == 0)
619613a2f6bSGordon Ross 			break;
620613a2f6bSGordon Ross 		slen++;
621613a2f6bSGordon Ross 	}
622613a2f6bSGordon Ross 
623613a2f6bSGordon Ross 	/*
624613a2f6bSGordon Ross 	 * Now read the (OEM) string for real.
625613a2f6bSGordon Ross 	 * No need to re-check errors.
626613a2f6bSGordon Ross 	 */
627613a2f6bSGordon Ross 	tstr = malloc(slen + 1);
628613a2f6bSGordon Ross 	if (tstr == NULL)
629613a2f6bSGordon Ross 		return (ENOMEM);
630613a2f6bSGordon Ross 	mbp = real_mbp;
631613a2f6bSGordon Ross 	for (i = 0; i < slen; i++) {
63202d09e03SGordon Ross 		md_get_uint8(mbp, &ch);
633613a2f6bSGordon Ross 		tstr[i] = ch;
634613a2f6bSGordon Ross 	}
635613a2f6bSGordon Ross 	tstr[i] = 0;
63602d09e03SGordon Ross 	md_get_uint8(mbp, NULL);
637613a2f6bSGordon Ross 
638613a2f6bSGordon Ross 	/*
639613a2f6bSGordon Ross 	 * Convert OEM to UTF-8
640613a2f6bSGordon Ross 	 */
641613a2f6bSGordon Ross 	ostr = convert_wincs_to_utf8(tstr);
642613a2f6bSGordon Ross 	free(tstr);
643613a2f6bSGordon Ross 	if (ostr == NULL)
644613a2f6bSGordon Ross 		return (ENOMEM);
645613a2f6bSGordon Ross 
646613a2f6bSGordon Ross 	*str_pp = ostr;
647613a2f6bSGordon Ross 	return (0);
648613a2f6bSGordon Ross }
649613a2f6bSGordon Ross 
650613a2f6bSGordon Ross /*
651613a2f6bSGordon Ross  * Get a UCS-2LE string from the mbuf chain, and
652613a2f6bSGordon Ross  * convert it to UTF-8.
653613a2f6bSGordon Ross  *
65402d09e03SGordon Ross  * Similar to md_get_astring above.
655613a2f6bSGordon Ross  */
656613a2f6bSGordon Ross int
65702d09e03SGordon Ross md_get_ustring(mdchain_t *real_mbp, char **str_pp)
658613a2f6bSGordon Ross {
65902d09e03SGordon Ross 	mdchain_t tmp_mb, *mbp;
660613a2f6bSGordon Ross 	uint16_t *tstr;
661613a2f6bSGordon Ross 	char *ostr;
662613a2f6bSGordon Ross 	int err, i, slen;
663613a2f6bSGordon Ross 	uint16_t ch;
664613a2f6bSGordon Ross 
665613a2f6bSGordon Ross 	/*
666613a2f6bSGordon Ross 	 * First, align(2) on the real_mbp
667613a2f6bSGordon Ross 	 */
668613a2f6bSGordon Ross 	if (((uintptr_t)real_mbp->mb_pos) & 1)
66902d09e03SGordon Ross 		md_get_uint8(real_mbp, NULL);
670613a2f6bSGordon Ross 
671613a2f6bSGordon Ross 	/*
672613a2f6bSGordon Ross 	 * Next, figure out the string length.
673613a2f6bSGordon Ross 	 * Use a copy of the real_mbp so we don't
674613a2f6bSGordon Ross 	 * actually consume it here, then search for
675613a2f6bSGordon Ross 	 * the null (or end of data).
676613a2f6bSGordon Ross 	 */
677613a2f6bSGordon Ross 	bcopy(real_mbp, &tmp_mb, sizeof (tmp_mb));
678613a2f6bSGordon Ross 	mbp = &tmp_mb;
679613a2f6bSGordon Ross 	slen = 0;
680613a2f6bSGordon Ross 	for (;;) {
68102d09e03SGordon Ross 		err = md_get_uint16le(mbp, &ch);
682613a2f6bSGordon Ross 		if (err)
683613a2f6bSGordon Ross 			break;
684613a2f6bSGordon Ross 		if (ch == 0)
685613a2f6bSGordon Ross 			break;
686613a2f6bSGordon Ross 		slen++;
687613a2f6bSGordon Ross 	}
688613a2f6bSGordon Ross 
689613a2f6bSGordon Ross 	/*
690613a2f6bSGordon Ross 	 * Now read the (UCS-2) string for real.
691613a2f6bSGordon Ross 	 * No need to re-check errors.  Note:
692613a2f6bSGordon Ross 	 * This puts the UCS-2 in NATIVE order!
693613a2f6bSGordon Ross 	 */
694613a2f6bSGordon Ross 	tstr = calloc(slen + 1, 2);
695613a2f6bSGordon Ross 	if (tstr == NULL)
696613a2f6bSGordon Ross 		return (ENOMEM);
697613a2f6bSGordon Ross 	mbp = real_mbp;
698613a2f6bSGordon Ross 	for (i = 0; i < slen; i++) {
69902d09e03SGordon Ross 		md_get_uint16le(mbp, &ch);
700613a2f6bSGordon Ross 		tstr[i] = ch;
701613a2f6bSGordon Ross 	}
702613a2f6bSGordon Ross 	tstr[i] = 0;
70302d09e03SGordon Ross 	md_get_uint16le(mbp, NULL);
704613a2f6bSGordon Ross 
705613a2f6bSGordon Ross 	/*
706613a2f6bSGordon Ross 	 * Convert UCS-2 (native!) to UTF-8
707613a2f6bSGordon Ross 	 */
708613a2f6bSGordon Ross 	ostr = convert_unicode_to_utf8(tstr);
709613a2f6bSGordon Ross 	free(tstr);
710613a2f6bSGordon Ross 	if (ostr == NULL)
711613a2f6bSGordon Ross 		return (ENOMEM);
712613a2f6bSGordon Ross 
713613a2f6bSGordon Ross 	*str_pp = ostr;
714613a2f6bSGordon Ross 	return (0);
715613a2f6bSGordon Ross }
716