xref: /titanic_50/usr/src/lib/libsmbfs/smb/mbuf.c (revision 613a2f6ba31e891e3d947a356daf5e563d43c1ce)
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*613a2f6bSGordon 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"
54*613a2f6bSGordon Ross #include "charsets.h"
554bff34e3Sthurlow 
564bff34e3Sthurlow static int
574bff34e3Sthurlow m_get(size_t len, struct mbuf **mpp)
584bff34e3Sthurlow {
594bff34e3Sthurlow 	struct mbuf *m;
604bff34e3Sthurlow 
617568150aSgwr 	assert(len < 0x100000); /* sanity */
627568150aSgwr 
634bff34e3Sthurlow 	len = M_ALIGN(len);
644bff34e3Sthurlow 	if (len < M_MINSIZE)
654bff34e3Sthurlow 		len = M_MINSIZE;
664bff34e3Sthurlow 	m = malloc(M_BASESIZE + len);
674bff34e3Sthurlow 	if (m == NULL)
684bff34e3Sthurlow 		return (ENOMEM);
694bff34e3Sthurlow 	bzero(m, M_BASESIZE + len);
704bff34e3Sthurlow 	m->m_maxlen = len;
714bff34e3Sthurlow 	m->m_data = M_TOP(m);
724bff34e3Sthurlow 	*mpp = m;
734bff34e3Sthurlow 	return (0);
744bff34e3Sthurlow }
754bff34e3Sthurlow 
764bff34e3Sthurlow static void
774bff34e3Sthurlow m_free(struct mbuf *m)
784bff34e3Sthurlow {
794bff34e3Sthurlow 	free(m);
804bff34e3Sthurlow }
814bff34e3Sthurlow 
82*613a2f6bSGordon Ross void
834bff34e3Sthurlow m_freem(struct mbuf *m0)
844bff34e3Sthurlow {
854bff34e3Sthurlow 	struct mbuf *m;
864bff34e3Sthurlow 
874bff34e3Sthurlow 	while (m0) {
884bff34e3Sthurlow 		m = m0->m_next;
894bff34e3Sthurlow 		m_free(m0);
904bff34e3Sthurlow 		m0 = m;
914bff34e3Sthurlow 	}
924bff34e3Sthurlow }
934bff34e3Sthurlow 
94*613a2f6bSGordon Ross size_t
954bff34e3Sthurlow m_totlen(struct mbuf *m0)
964bff34e3Sthurlow {
974bff34e3Sthurlow 	struct mbuf *m = m0;
984bff34e3Sthurlow 	int len = 0;
994bff34e3Sthurlow 
1004bff34e3Sthurlow 	while (m) {
1014bff34e3Sthurlow 		len += m->m_len;
1024bff34e3Sthurlow 		m = m->m_next;
1034bff34e3Sthurlow 	}
1044bff34e3Sthurlow 	return (len);
1054bff34e3Sthurlow }
1064bff34e3Sthurlow 
1074bff34e3Sthurlow int
1084bff34e3Sthurlow m_lineup(struct mbuf *m0, struct mbuf **mpp)
1094bff34e3Sthurlow {
1104bff34e3Sthurlow 	struct mbuf *nm, *m;
1114bff34e3Sthurlow 	char *dp;
1124bff34e3Sthurlow 	size_t len;
1134bff34e3Sthurlow 	int error;
1144bff34e3Sthurlow 
1154bff34e3Sthurlow 	if (m0->m_next == NULL) {
1164bff34e3Sthurlow 		*mpp = m0;
1174bff34e3Sthurlow 		return (0);
1184bff34e3Sthurlow 	}
1194bff34e3Sthurlow 	if ((error = m_get(m_totlen(m0), &nm)) != 0)
1204bff34e3Sthurlow 		return (error);
1214bff34e3Sthurlow 	dp = mtod(nm, char *);
1224bff34e3Sthurlow 	while (m0) {
1234bff34e3Sthurlow 		len = m0->m_len;
1244bff34e3Sthurlow 		bcopy(m0->m_data, dp, len);
1254bff34e3Sthurlow 		dp += len;
1264bff34e3Sthurlow 		m = m0->m_next;
1274bff34e3Sthurlow 		m_free(m0);
1284bff34e3Sthurlow 		m0 = m;
1294bff34e3Sthurlow 	}
1304bff34e3Sthurlow 	*mpp = nm;
1314bff34e3Sthurlow 	return (0);
1324bff34e3Sthurlow }
1334bff34e3Sthurlow 
1344bff34e3Sthurlow int
1354bff34e3Sthurlow mb_init(struct mbdata *mbp, size_t size)
1364bff34e3Sthurlow {
1374bff34e3Sthurlow 	struct mbuf *m;
1384bff34e3Sthurlow 	int error;
1394bff34e3Sthurlow 
1404bff34e3Sthurlow 	if ((error = m_get(size, &m)) != 0)
1414bff34e3Sthurlow 		return (error);
1424bff34e3Sthurlow 	return (mb_initm(mbp, m));
1434bff34e3Sthurlow }
1444bff34e3Sthurlow 
1454bff34e3Sthurlow int
1464bff34e3Sthurlow mb_initm(struct mbdata *mbp, struct mbuf *m)
1474bff34e3Sthurlow {
1484bff34e3Sthurlow 	bzero(mbp, sizeof (*mbp));
1494bff34e3Sthurlow 	mbp->mb_top = mbp->mb_cur = m;
1504bff34e3Sthurlow 	mbp->mb_pos = mtod(m, char *);
1514bff34e3Sthurlow 	return (0);
1524bff34e3Sthurlow }
1534bff34e3Sthurlow 
1544bff34e3Sthurlow int
1554bff34e3Sthurlow mb_done(struct mbdata *mbp)
1564bff34e3Sthurlow {
1574bff34e3Sthurlow 	if (mbp->mb_top) {
1584bff34e3Sthurlow 		m_freem(mbp->mb_top);
1594bff34e3Sthurlow 		mbp->mb_top = NULL;
1604bff34e3Sthurlow 	}
1614bff34e3Sthurlow 	return (0);
1624bff34e3Sthurlow }
1634bff34e3Sthurlow 
1644bff34e3Sthurlow int
1654bff34e3Sthurlow m_getm(struct mbuf *top, size_t len, struct mbuf **mpp)
1664bff34e3Sthurlow {
1674bff34e3Sthurlow 	struct mbuf *m, *mp;
1687568150aSgwr 	int  error, ts;
1694bff34e3Sthurlow 
1704bff34e3Sthurlow 	for (mp = top; ; mp = mp->m_next) {
1717568150aSgwr 		ts = M_TRAILINGSPACE(mp);
1727568150aSgwr 		if (len <= ts)
1737568150aSgwr 			goto out;
1747568150aSgwr 		len -= ts;
1754bff34e3Sthurlow 		if (mp->m_next == NULL)
1764bff34e3Sthurlow 			break;
1774bff34e3Sthurlow 
1784bff34e3Sthurlow 	}
1794bff34e3Sthurlow 	if (len > 0) {
1804bff34e3Sthurlow 		if ((error = m_get(len, &m)) != 0)
1814bff34e3Sthurlow 			return (error);
1824bff34e3Sthurlow 		mp->m_next = m;
1834bff34e3Sthurlow 	}
1847568150aSgwr out:
1854bff34e3Sthurlow 	*mpp = top;
1864bff34e3Sthurlow 	return (0);
1874bff34e3Sthurlow }
1884bff34e3Sthurlow 
1894bff34e3Sthurlow /*
1904bff34e3Sthurlow  * Routines to put data in a buffer
1914bff34e3Sthurlow  */
1924bff34e3Sthurlow 
1934bff34e3Sthurlow /*
1944bff34e3Sthurlow  * Check if object of size 'size' fit to the current position and
1954bff34e3Sthurlow  * allocate new mbuf if not. Advance pointers and increase length of mbuf(s).
1964bff34e3Sthurlow  * Return pointer to the object placeholder or NULL if any error occured.
1974bff34e3Sthurlow  */
1984bff34e3Sthurlow int
1994bff34e3Sthurlow mb_fit(struct mbdata *mbp, size_t size, char **pp)
2004bff34e3Sthurlow {
2014bff34e3Sthurlow 	struct mbuf *m, *mn;
2024bff34e3Sthurlow 	int error;
2034bff34e3Sthurlow 
2044bff34e3Sthurlow 	m = mbp->mb_cur;
2054bff34e3Sthurlow 	if (M_TRAILINGSPACE(m) < (int)size) {
2064bff34e3Sthurlow 		if ((error = m_get(size, &mn)) != 0)
2074bff34e3Sthurlow 			return (error);
2084bff34e3Sthurlow 		mbp->mb_pos = mtod(mn, char *);
2094bff34e3Sthurlow 		mbp->mb_cur = m->m_next = mn;
2104bff34e3Sthurlow 		m = mn;
2114bff34e3Sthurlow 	}
2124bff34e3Sthurlow 	m->m_len += size;
2134bff34e3Sthurlow 	*pp = mbp->mb_pos;
2144bff34e3Sthurlow 	mbp->mb_pos += size;
2154bff34e3Sthurlow 	mbp->mb_count += size;
2164bff34e3Sthurlow 	return (0);
2174bff34e3Sthurlow }
2184bff34e3Sthurlow 
2194bff34e3Sthurlow int
2204bff34e3Sthurlow mb_put_uint8(struct mbdata *mbp, uint8_t x)
2214bff34e3Sthurlow {
2229c9af259SGordon Ross 	uint8_t y = x;
223*613a2f6bSGordon Ross 	return (mb_put_mem(mbp, &y, sizeof (y)));
2244bff34e3Sthurlow }
2254bff34e3Sthurlow 
2264bff34e3Sthurlow int
2274bff34e3Sthurlow mb_put_uint16be(struct mbdata *mbp, uint16_t x)
2284bff34e3Sthurlow {
2299c9af259SGordon Ross 	uint16_t y = htobes(x);
230*613a2f6bSGordon Ross 	return (mb_put_mem(mbp, &y, sizeof (y)));
2314bff34e3Sthurlow }
2324bff34e3Sthurlow 
2334bff34e3Sthurlow int
2344bff34e3Sthurlow mb_put_uint16le(struct mbdata *mbp, uint16_t x)
2354bff34e3Sthurlow {
2369c9af259SGordon Ross 	uint16_t y = htoles(x);
237*613a2f6bSGordon Ross 	return (mb_put_mem(mbp, &y, sizeof (y)));
2384bff34e3Sthurlow }
2394bff34e3Sthurlow 
2404bff34e3Sthurlow int
2414bff34e3Sthurlow mb_put_uint32be(struct mbdata *mbp, uint32_t x)
2424bff34e3Sthurlow {
2439c9af259SGordon Ross 	uint32_t y = htobel(x);
244*613a2f6bSGordon Ross 	return (mb_put_mem(mbp, &y, sizeof (y)));
2454bff34e3Sthurlow }
2464bff34e3Sthurlow 
2474bff34e3Sthurlow int
2484bff34e3Sthurlow mb_put_uint32le(struct mbdata *mbp, uint32_t x)
2494bff34e3Sthurlow {
2509c9af259SGordon Ross 	uint32_t y = htolel(x);
251*613a2f6bSGordon Ross 	return (mb_put_mem(mbp, &y, sizeof (y)));
2524bff34e3Sthurlow }
2534bff34e3Sthurlow 
2544bff34e3Sthurlow int
2554bff34e3Sthurlow mb_put_uint64be(struct mbdata *mbp, uint64_t x)
2564bff34e3Sthurlow {
2579c9af259SGordon Ross 	uint64_t y = htobeq(x);
258*613a2f6bSGordon Ross 	return (mb_put_mem(mbp, &y, sizeof (y)));
2594bff34e3Sthurlow }
2604bff34e3Sthurlow 
2614bff34e3Sthurlow int
2624bff34e3Sthurlow mb_put_uint64le(struct mbdata *mbp, uint64_t x)
2634bff34e3Sthurlow {
2649c9af259SGordon Ross 	uint64_t y = htoleq(x);
265*613a2f6bSGordon Ross 	return (mb_put_mem(mbp, &y, sizeof (y)));
2664bff34e3Sthurlow }
2674bff34e3Sthurlow 
2684bff34e3Sthurlow int
269*613a2f6bSGordon Ross mb_put_mem(struct mbdata *mbp, const void *vmem, size_t size)
2704bff34e3Sthurlow {
2714bff34e3Sthurlow 	struct mbuf *m;
272*613a2f6bSGordon Ross 	const char *src;
2734bff34e3Sthurlow 	char  *dst;
2744bff34e3Sthurlow 	size_t cplen;
2754bff34e3Sthurlow 	int error;
2764bff34e3Sthurlow 
2774bff34e3Sthurlow 	if (size == 0)
2784bff34e3Sthurlow 		return (0);
279*613a2f6bSGordon Ross 
280*613a2f6bSGordon Ross 	src = vmem;
2814bff34e3Sthurlow 	m = mbp->mb_cur;
2824bff34e3Sthurlow 	if ((error = m_getm(m, size, &m)) != 0)
2834bff34e3Sthurlow 		return (error);
2844bff34e3Sthurlow 	while (size > 0) {
2854bff34e3Sthurlow 		cplen = M_TRAILINGSPACE(m);
2864bff34e3Sthurlow 		if (cplen == 0) {
2874bff34e3Sthurlow 			m = m->m_next;
2884bff34e3Sthurlow 			continue;
2894bff34e3Sthurlow 		}
2904bff34e3Sthurlow 		if (cplen > size)
2914bff34e3Sthurlow 			cplen = size;
2924bff34e3Sthurlow 		dst = mtod(m, char *) + m->m_len;
293*613a2f6bSGordon Ross 		if (src) {
294*613a2f6bSGordon Ross 			bcopy(src, dst, cplen);
295*613a2f6bSGordon Ross 			src += cplen;
2964bff34e3Sthurlow 		} else
2974bff34e3Sthurlow 			bzero(dst, cplen);
2984bff34e3Sthurlow 		size -= cplen;
2994bff34e3Sthurlow 		m->m_len += cplen;
3004bff34e3Sthurlow 		mbp->mb_count += cplen;
3014bff34e3Sthurlow 	}
3024bff34e3Sthurlow 	mbp->mb_pos = mtod(m, char *) + m->m_len;
3034bff34e3Sthurlow 	mbp->mb_cur = m;
3044bff34e3Sthurlow 	return (0);
3054bff34e3Sthurlow }
3064bff34e3Sthurlow 
307*613a2f6bSGordon Ross /*
308*613a2f6bSGordon Ross  * Append another mbuf to the mbuf chain.
309*613a2f6bSGordon Ross  * If what we're appending is smaller than
310*613a2f6bSGordon Ross  * the current trailing space, just copy.
311*613a2f6bSGordon Ross  * This always consumes the passed mbuf.
312*613a2f6bSGordon Ross  */
3134bff34e3Sthurlow int
3144bff34e3Sthurlow mb_put_mbuf(struct mbdata *mbp, struct mbuf *m)
3154bff34e3Sthurlow {
316*613a2f6bSGordon Ross 	struct mbuf *cm = mbp->mb_cur;
317*613a2f6bSGordon Ross 	int ts = M_TRAILINGSPACE(cm);
318*613a2f6bSGordon Ross 
319*613a2f6bSGordon Ross 	if (m->m_next == NULL && m->m_len <= ts) {
320*613a2f6bSGordon Ross 		/* just copy */
321*613a2f6bSGordon Ross 		mb_put_mem(mbp, m->m_data, m->m_len);
322*613a2f6bSGordon Ross 		m_freem(m);
323*613a2f6bSGordon Ross 		return (0);
324*613a2f6bSGordon Ross 	}
325*613a2f6bSGordon Ross 
326*613a2f6bSGordon Ross 	cm->m_next = m;
3274bff34e3Sthurlow 	while (m) {
3284bff34e3Sthurlow 		mbp->mb_count += m->m_len;
3294bff34e3Sthurlow 		if (m->m_next == NULL)
3304bff34e3Sthurlow 			break;
3314bff34e3Sthurlow 		m = m->m_next;
3324bff34e3Sthurlow 	}
3334bff34e3Sthurlow 	mbp->mb_pos = mtod(m, char *) + m->m_len;
3344bff34e3Sthurlow 	mbp->mb_cur = m;
3354bff34e3Sthurlow 	return (0);
3364bff34e3Sthurlow }
3374bff34e3Sthurlow 
338*613a2f6bSGordon Ross /*
339*613a2f6bSGordon Ross  * Convenience function to put an OEM or Unicode string,
340*613a2f6bSGordon Ross  * null terminated, and aligned if necessary.
341*613a2f6bSGordon Ross  */
3424bff34e3Sthurlow int
343*613a2f6bSGordon Ross mb_put_dstring(struct mbdata *mbp, const char *s, int uc)
3444bff34e3Sthurlow {
345*613a2f6bSGordon Ross 	int err;
3464bff34e3Sthurlow 
347*613a2f6bSGordon Ross 	if (uc) {
348*613a2f6bSGordon Ross 		/* Put Unicode.  align(2) first. */
349*613a2f6bSGordon Ross 		if (mbp->mb_count & 1)
350*613a2f6bSGordon Ross 			mb_put_uint8(mbp, 0);
351*613a2f6bSGordon Ross 		err = mb_put_ustring(mbp, s);
352*613a2f6bSGordon Ross 	} else {
353*613a2f6bSGordon Ross 		/* Put ASCII (really OEM) */
354*613a2f6bSGordon Ross 		err = mb_put_astring(mbp, s);
3554bff34e3Sthurlow 	}
356*613a2f6bSGordon Ross 
357*613a2f6bSGordon Ross 	return (err);
358*613a2f6bSGordon Ross }
359*613a2f6bSGordon Ross 
360*613a2f6bSGordon Ross /*
361*613a2f6bSGordon Ross  * Put an ASCII string (really OEM), given a UTF-8 string.
362*613a2f6bSGordon Ross  */
363*613a2f6bSGordon Ross int
364*613a2f6bSGordon Ross mb_put_astring(struct mbdata *mbp, const char *s)
365*613a2f6bSGordon Ross {
366*613a2f6bSGordon Ross 	char *abuf;
367*613a2f6bSGordon Ross 	int err, len;
368*613a2f6bSGordon Ross 
369*613a2f6bSGordon Ross 	abuf = convert_utf8_to_wincs(s);
370*613a2f6bSGordon Ross 	if (abuf == NULL)
371*613a2f6bSGordon Ross 		return (ENOMEM);
372*613a2f6bSGordon Ross 	len = strlen(abuf) + 1;
373*613a2f6bSGordon Ross 	err = mb_put_mem(mbp, abuf, len);
374*613a2f6bSGordon Ross 	free(abuf);
375*613a2f6bSGordon Ross 	return (err);
376*613a2f6bSGordon Ross }
377*613a2f6bSGordon Ross 
378*613a2f6bSGordon Ross /*
379*613a2f6bSGordon Ross  * Put UCS-2LE, given a UTF-8 string.
380*613a2f6bSGordon Ross  */
381*613a2f6bSGordon Ross int
382*613a2f6bSGordon Ross mb_put_ustring(struct mbdata *mbp, const char *s)
383*613a2f6bSGordon Ross {
384*613a2f6bSGordon Ross 	uint16_t *ubuf;
385*613a2f6bSGordon Ross 	int err, len;
386*613a2f6bSGordon Ross 
387*613a2f6bSGordon Ross 	ubuf = convert_utf8_to_leunicode(s);
388*613a2f6bSGordon Ross 	if (ubuf == NULL)
389*613a2f6bSGordon Ross 		return (ENOMEM);
390*613a2f6bSGordon Ross 	len = unicode_strlen(ubuf) + 1;
391*613a2f6bSGordon Ross 	err = mb_put_mem(mbp, ubuf, (len << 1));
392*613a2f6bSGordon Ross 	free(ubuf);
393*613a2f6bSGordon Ross 	return (err);
3944bff34e3Sthurlow }
3954bff34e3Sthurlow 
3964bff34e3Sthurlow /*
3974bff34e3Sthurlow  * Routines for fetching data from an mbuf chain
3984bff34e3Sthurlow  */
3994bff34e3Sthurlow #define	mb_left(m, p)	(mtod(m, char *) + (m)->m_len - (p))
4004bff34e3Sthurlow 
4014bff34e3Sthurlow int
4024bff34e3Sthurlow mb_get_uint8(struct mbdata *mbp, uint8_t *x)
4034bff34e3Sthurlow {
404*613a2f6bSGordon Ross 	return (mb_get_mem(mbp, x, 1));
4054bff34e3Sthurlow }
4064bff34e3Sthurlow 
4074bff34e3Sthurlow int
4084bff34e3Sthurlow mb_get_uint16(struct mbdata *mbp, uint16_t *x)
4094bff34e3Sthurlow {
410*613a2f6bSGordon Ross 	return (mb_get_mem(mbp, x, 2));
4114bff34e3Sthurlow }
4124bff34e3Sthurlow 
4134bff34e3Sthurlow int
4144bff34e3Sthurlow mb_get_uint16le(struct mbdata *mbp, uint16_t *x)
4154bff34e3Sthurlow {
4164bff34e3Sthurlow 	uint16_t v;
417*613a2f6bSGordon Ross 	int err;
4184bff34e3Sthurlow 
419*613a2f6bSGordon Ross 	if ((err = mb_get_mem(mbp, &v, 2)) != 0)
420*613a2f6bSGordon Ross 		return (err);
4214bff34e3Sthurlow 	if (x != NULL)
4224bff34e3Sthurlow 		*x = letohs(v);
423*613a2f6bSGordon Ross 	return (0);
4244bff34e3Sthurlow }
4254bff34e3Sthurlow 
4264bff34e3Sthurlow int
4274bff34e3Sthurlow mb_get_uint16be(struct mbdata *mbp, uint16_t *x) {
4284bff34e3Sthurlow 	uint16_t v;
429*613a2f6bSGordon Ross 	int err;
4304bff34e3Sthurlow 
431*613a2f6bSGordon Ross 	if ((err = mb_get_mem(mbp, &v, 2)) != 0)
432*613a2f6bSGordon Ross 		return (err);
4334bff34e3Sthurlow 	if (x != NULL)
4344bff34e3Sthurlow 		*x = betohs(v);
435*613a2f6bSGordon Ross 	return (0);
4364bff34e3Sthurlow }
4374bff34e3Sthurlow 
4384bff34e3Sthurlow int
4394bff34e3Sthurlow mb_get_uint32(struct mbdata *mbp, uint32_t *x)
4404bff34e3Sthurlow {
441*613a2f6bSGordon Ross 	return (mb_get_mem(mbp, x, 4));
4424bff34e3Sthurlow }
4434bff34e3Sthurlow 
4444bff34e3Sthurlow int
4454bff34e3Sthurlow mb_get_uint32be(struct mbdata *mbp, uint32_t *x)
4464bff34e3Sthurlow {
4474bff34e3Sthurlow 	uint32_t v;
448*613a2f6bSGordon Ross 	int err;
4494bff34e3Sthurlow 
450*613a2f6bSGordon Ross 	if ((err = mb_get_mem(mbp, &v, 4)) != 0)
451*613a2f6bSGordon Ross 		return (err);
4524bff34e3Sthurlow 	if (x != NULL)
4534bff34e3Sthurlow 		*x = betohl(v);
454*613a2f6bSGordon Ross 	return (0);
4554bff34e3Sthurlow }
4564bff34e3Sthurlow 
4574bff34e3Sthurlow int
4584bff34e3Sthurlow mb_get_uint32le(struct mbdata *mbp, uint32_t *x)
4594bff34e3Sthurlow {
4604bff34e3Sthurlow 	uint32_t v;
461*613a2f6bSGordon Ross 	int err;
4624bff34e3Sthurlow 
463*613a2f6bSGordon Ross 	if ((err = mb_get_mem(mbp, &v, 4)) != 0)
464*613a2f6bSGordon Ross 		return (err);
4654bff34e3Sthurlow 	if (x != NULL)
4664bff34e3Sthurlow 		*x = letohl(v);
467*613a2f6bSGordon Ross 	return (0);
4684bff34e3Sthurlow }
4694bff34e3Sthurlow 
4704bff34e3Sthurlow int
4714bff34e3Sthurlow mb_get_uint64(struct mbdata *mbp, uint64_t *x)
4724bff34e3Sthurlow {
473*613a2f6bSGordon Ross 	return (mb_get_mem(mbp, x, 8));
4744bff34e3Sthurlow }
4754bff34e3Sthurlow 
4764bff34e3Sthurlow int
4774bff34e3Sthurlow mb_get_uint64be(struct mbdata *mbp, uint64_t *x)
4784bff34e3Sthurlow {
4794bff34e3Sthurlow 	uint64_t v;
480*613a2f6bSGordon Ross 	int err;
4814bff34e3Sthurlow 
482*613a2f6bSGordon Ross 	if ((err = mb_get_mem(mbp, &v, 8)) != 0)
483*613a2f6bSGordon Ross 		return (err);
4844bff34e3Sthurlow 	if (x != NULL)
4854bff34e3Sthurlow 		*x = betohq(v);
486*613a2f6bSGordon Ross 	return (0);
4874bff34e3Sthurlow }
4884bff34e3Sthurlow 
4894bff34e3Sthurlow int
4904bff34e3Sthurlow mb_get_uint64le(struct mbdata *mbp, uint64_t *x)
4914bff34e3Sthurlow {
4924bff34e3Sthurlow 	uint64_t v;
493*613a2f6bSGordon Ross 	int err;
4944bff34e3Sthurlow 
495*613a2f6bSGordon Ross 	if ((err = mb_get_mem(mbp, &v, 8)) != 0)
496*613a2f6bSGordon Ross 		return (err);
4974bff34e3Sthurlow 	if (x != NULL)
4984bff34e3Sthurlow 		*x = letohq(v);
499*613a2f6bSGordon Ross 	return (0);
5004bff34e3Sthurlow }
5014bff34e3Sthurlow 
5024bff34e3Sthurlow int
503*613a2f6bSGordon Ross mb_get_mem(struct mbdata *mbp, void *vmem, size_t size)
5044bff34e3Sthurlow {
5054bff34e3Sthurlow 	struct mbuf *m = mbp->mb_cur;
506*613a2f6bSGordon Ross 	char *dst = vmem;
5074bff34e3Sthurlow 	uint_t count;
5084bff34e3Sthurlow 
5094bff34e3Sthurlow 	while (size > 0) {
5104bff34e3Sthurlow 		if (m == NULL) {
511*613a2f6bSGordon Ross 			/* DPRINT("incomplete copy"); */
5124bff34e3Sthurlow 			return (EBADRPC);
5134bff34e3Sthurlow 		}
5144bff34e3Sthurlow 		count = mb_left(m, mbp->mb_pos);
5154bff34e3Sthurlow 		if (count == 0) {
5164bff34e3Sthurlow 			mbp->mb_cur = m = m->m_next;
5174bff34e3Sthurlow 			if (m)
5184bff34e3Sthurlow 				mbp->mb_pos = mtod(m, char *);
5194bff34e3Sthurlow 			continue;
5204bff34e3Sthurlow 		}
5214bff34e3Sthurlow 		if (count > size)
5224bff34e3Sthurlow 			count = size;
5234bff34e3Sthurlow 		size -= count;
524*613a2f6bSGordon Ross 		if (dst) {
5254bff34e3Sthurlow 			if (count == 1) {
526*613a2f6bSGordon Ross 				*dst++ = *mbp->mb_pos;
5274bff34e3Sthurlow 			} else {
528*613a2f6bSGordon Ross 				bcopy(mbp->mb_pos, dst, count);
529*613a2f6bSGordon Ross 				dst += count;
5304bff34e3Sthurlow 			}
5314bff34e3Sthurlow 		}
5324bff34e3Sthurlow 		mbp->mb_pos += count;
5334bff34e3Sthurlow 	}
5344bff34e3Sthurlow 	return (0);
5354bff34e3Sthurlow }
536*613a2f6bSGordon Ross 
537*613a2f6bSGordon Ross /*
538*613a2f6bSGordon Ross  * Get the next SIZE bytes as a separate mblk.
539*613a2f6bSGordon Ross  * Nothing fancy here - just copy.
540*613a2f6bSGordon Ross  */
541*613a2f6bSGordon Ross int
542*613a2f6bSGordon Ross mb_get_mbuf(struct mbdata *mbp, int size, struct mbuf **ret)
543*613a2f6bSGordon Ross {
544*613a2f6bSGordon Ross 	mbuf_t *m;
545*613a2f6bSGordon Ross 	int err;
546*613a2f6bSGordon Ross 
547*613a2f6bSGordon Ross 	err = m_get(size, &m);
548*613a2f6bSGordon Ross 	if (err)
549*613a2f6bSGordon Ross 		return (err);
550*613a2f6bSGordon Ross 
551*613a2f6bSGordon Ross 	err = mb_get_mem(mbp, m->m_data, size);
552*613a2f6bSGordon Ross 	if (err) {
553*613a2f6bSGordon Ross 		m_freem(m);
554*613a2f6bSGordon Ross 		return (err);
555*613a2f6bSGordon Ross 	}
556*613a2f6bSGordon Ross 	m->m_len = size;
557*613a2f6bSGordon Ross 	*ret = m;
558*613a2f6bSGordon Ross 
559*613a2f6bSGordon Ross 	return (0);
560*613a2f6bSGordon Ross }
561*613a2f6bSGordon Ross 
562*613a2f6bSGordon Ross /*
563*613a2f6bSGordon Ross  * Get a string from the mbuf chain,
564*613a2f6bSGordon Ross  * either Unicode or OEM chars.
565*613a2f6bSGordon Ross  */
566*613a2f6bSGordon Ross int
567*613a2f6bSGordon Ross mb_get_string(struct mbdata *mbp, char **str_pp, int uc)
568*613a2f6bSGordon Ross {
569*613a2f6bSGordon Ross 	int err;
570*613a2f6bSGordon Ross 
571*613a2f6bSGordon Ross 	if (uc)
572*613a2f6bSGordon Ross 		err = mb_get_ustring(mbp, str_pp);
573*613a2f6bSGordon Ross 	else
574*613a2f6bSGordon Ross 		err = mb_get_astring(mbp, str_pp);
575*613a2f6bSGordon Ross 	return (err);
576*613a2f6bSGordon Ross }
577*613a2f6bSGordon Ross 
578*613a2f6bSGordon Ross /*
579*613a2f6bSGordon Ross  * Get an ASCII (really OEM) string from the mbuf chain
580*613a2f6bSGordon Ross  * and convert it to UTF-8
581*613a2f6bSGordon Ross  * Similar to mb_get_ustring below.
582*613a2f6bSGordon Ross  */
583*613a2f6bSGordon Ross int
584*613a2f6bSGordon Ross mb_get_astring(struct mbdata *real_mbp, char **str_pp)
585*613a2f6bSGordon Ross {
586*613a2f6bSGordon Ross 	struct mbdata tmp_mb, *mbp;
587*613a2f6bSGordon Ross 	char *tstr, *ostr;
588*613a2f6bSGordon Ross 	int err, i, slen;
589*613a2f6bSGordon Ross 	uint8_t ch;
590*613a2f6bSGordon Ross 
591*613a2f6bSGordon Ross 	/*
592*613a2f6bSGordon Ross 	 * First, figure out the string length.
593*613a2f6bSGordon Ross 	 * Use a copy of the real_mbp so we don't
594*613a2f6bSGordon Ross 	 * actually consume it here, then search for
595*613a2f6bSGordon Ross 	 * the null (or end of data).
596*613a2f6bSGordon Ross 	 */
597*613a2f6bSGordon Ross 	bcopy(real_mbp, &tmp_mb, sizeof (tmp_mb));
598*613a2f6bSGordon Ross 	mbp = &tmp_mb;
599*613a2f6bSGordon Ross 	slen = 0;
600*613a2f6bSGordon Ross 	for (;;) {
601*613a2f6bSGordon Ross 		err = mb_get_uint8(mbp, &ch);
602*613a2f6bSGordon Ross 		if (err)
603*613a2f6bSGordon Ross 			break;
604*613a2f6bSGordon Ross 		if (ch == 0)
605*613a2f6bSGordon Ross 			break;
606*613a2f6bSGordon Ross 		slen++;
607*613a2f6bSGordon Ross 	}
608*613a2f6bSGordon Ross 
609*613a2f6bSGordon Ross 	/*
610*613a2f6bSGordon Ross 	 * Now read the (OEM) string for real.
611*613a2f6bSGordon Ross 	 * No need to re-check errors.
612*613a2f6bSGordon Ross 	 */
613*613a2f6bSGordon Ross 	tstr = malloc(slen + 1);
614*613a2f6bSGordon Ross 	if (tstr == NULL)
615*613a2f6bSGordon Ross 		return (ENOMEM);
616*613a2f6bSGordon Ross 	mbp = real_mbp;
617*613a2f6bSGordon Ross 	for (i = 0; i < slen; i++) {
618*613a2f6bSGordon Ross 		mb_get_uint8(mbp, &ch);
619*613a2f6bSGordon Ross 		tstr[i] = ch;
620*613a2f6bSGordon Ross 	}
621*613a2f6bSGordon Ross 	tstr[i] = 0;
622*613a2f6bSGordon Ross 	mb_get_uint8(mbp, NULL);
623*613a2f6bSGordon Ross 
624*613a2f6bSGordon Ross 	/*
625*613a2f6bSGordon Ross 	 * Convert OEM to UTF-8
626*613a2f6bSGordon Ross 	 */
627*613a2f6bSGordon Ross 	ostr = convert_wincs_to_utf8(tstr);
628*613a2f6bSGordon Ross 	free(tstr);
629*613a2f6bSGordon Ross 	if (ostr == NULL)
630*613a2f6bSGordon Ross 		return (ENOMEM);
631*613a2f6bSGordon Ross 
632*613a2f6bSGordon Ross 	*str_pp = ostr;
633*613a2f6bSGordon Ross 	return (0);
634*613a2f6bSGordon Ross }
635*613a2f6bSGordon Ross 
636*613a2f6bSGordon Ross /*
637*613a2f6bSGordon Ross  * Get a UCS-2LE string from the mbuf chain, and
638*613a2f6bSGordon Ross  * convert it to UTF-8.
639*613a2f6bSGordon Ross  *
640*613a2f6bSGordon Ross  * Similar to mb_get_astring below.
641*613a2f6bSGordon Ross  */
642*613a2f6bSGordon Ross int
643*613a2f6bSGordon Ross mb_get_ustring(struct mbdata *real_mbp, char **str_pp)
644*613a2f6bSGordon Ross {
645*613a2f6bSGordon Ross 	struct mbdata tmp_mb, *mbp;
646*613a2f6bSGordon Ross 	uint16_t *tstr;
647*613a2f6bSGordon Ross 	char *ostr;
648*613a2f6bSGordon Ross 	int err, i, slen;
649*613a2f6bSGordon Ross 	uint16_t ch;
650*613a2f6bSGordon Ross 
651*613a2f6bSGordon Ross 	/*
652*613a2f6bSGordon Ross 	 * First, align(2) on the real_mbp
653*613a2f6bSGordon Ross 	 */
654*613a2f6bSGordon Ross 	if (((uintptr_t)real_mbp->mb_pos) & 1)
655*613a2f6bSGordon Ross 		mb_get_uint8(real_mbp, NULL);
656*613a2f6bSGordon Ross 
657*613a2f6bSGordon Ross 	/*
658*613a2f6bSGordon Ross 	 * Next, figure out the string length.
659*613a2f6bSGordon Ross 	 * Use a copy of the real_mbp so we don't
660*613a2f6bSGordon Ross 	 * actually consume it here, then search for
661*613a2f6bSGordon Ross 	 * the null (or end of data).
662*613a2f6bSGordon Ross 	 */
663*613a2f6bSGordon Ross 	bcopy(real_mbp, &tmp_mb, sizeof (tmp_mb));
664*613a2f6bSGordon Ross 	mbp = &tmp_mb;
665*613a2f6bSGordon Ross 	slen = 0;
666*613a2f6bSGordon Ross 	for (;;) {
667*613a2f6bSGordon Ross 		err = mb_get_uint16le(mbp, &ch);
668*613a2f6bSGordon Ross 		if (err)
669*613a2f6bSGordon Ross 			break;
670*613a2f6bSGordon Ross 		if (ch == 0)
671*613a2f6bSGordon Ross 			break;
672*613a2f6bSGordon Ross 		slen++;
673*613a2f6bSGordon Ross 	}
674*613a2f6bSGordon Ross 
675*613a2f6bSGordon Ross 	/*
676*613a2f6bSGordon Ross 	 * Now read the (UCS-2) string for real.
677*613a2f6bSGordon Ross 	 * No need to re-check errors.  Note:
678*613a2f6bSGordon Ross 	 * This puts the UCS-2 in NATIVE order!
679*613a2f6bSGordon Ross 	 */
680*613a2f6bSGordon Ross 	tstr = calloc(slen + 1, 2);
681*613a2f6bSGordon Ross 	if (tstr == NULL)
682*613a2f6bSGordon Ross 		return (ENOMEM);
683*613a2f6bSGordon Ross 	mbp = real_mbp;
684*613a2f6bSGordon Ross 	for (i = 0; i < slen; i++) {
685*613a2f6bSGordon Ross 		mb_get_uint16le(mbp, &ch);
686*613a2f6bSGordon Ross 		tstr[i] = ch;
687*613a2f6bSGordon Ross 	}
688*613a2f6bSGordon Ross 	tstr[i] = 0;
689*613a2f6bSGordon Ross 	mb_get_uint16le(mbp, NULL);
690*613a2f6bSGordon Ross 
691*613a2f6bSGordon Ross 	/*
692*613a2f6bSGordon Ross 	 * Convert UCS-2 (native!) to UTF-8
693*613a2f6bSGordon Ross 	 */
694*613a2f6bSGordon Ross 	ostr = convert_unicode_to_utf8(tstr);
695*613a2f6bSGordon Ross 	free(tstr);
696*613a2f6bSGordon Ross 	if (ostr == NULL)
697*613a2f6bSGordon Ross 		return (ENOMEM);
698*613a2f6bSGordon Ross 
699*613a2f6bSGordon Ross 	*str_pp = ostr;
700*613a2f6bSGordon Ross 	return (0);
701*613a2f6bSGordon Ross }
702