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
m_get(int len,struct mbuf ** mpp)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
m_free(struct mbuf * m)884bff34e3Sthurlow m_free(struct mbuf *m)
894bff34e3Sthurlow {
904bff34e3Sthurlow free(m);
914bff34e3Sthurlow }
924bff34e3Sthurlow
93613a2f6bSGordon Ross void
m_freem(struct mbuf * m0)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
m_totlen(struct mbuf * m0)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
m_lineup(struct mbuf * m0,struct mbuf ** mpp)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
mb_init(struct mbdata * mbp)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
mb_init_sz(struct mbdata * mbp,int size)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
mb_initm(struct mbdata * mbp,struct mbuf * m)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
mb_done(struct mbdata * mbp)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
m_getm(struct mbuf * top,int len,struct mbuf ** mpp)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 *
mb_reserve(mbchain_t * mbp,int size)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
mb_fit(mbchain_t * mbp,int size,char ** pp)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
mb_put_uint8(mbchain_t * mbp,uint8_t x)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
mb_put_uint16be(mbchain_t * mbp,uint16_t x)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
mb_put_uint16le(mbchain_t * mbp,uint16_t x)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
mb_put_uint32be(mbchain_t * mbp,uint32_t x)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
mb_put_uint32le(mbchain_t * mbp,uint32_t x)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
mb_put_uint64be(mbchain_t * mbp,uint64_t x)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
mb_put_uint64le(mbchain_t * mbp,uint64_t x)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
mb_put_mem(mbchain_t * mbp,const void * vmem,int size,int type)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
mb_put_mbuf(mbchain_t * mbp,struct mbuf * m)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
mb_put_string(mbchain_t * mbp,const char * s,int uc)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
mb_put_astring(mbchain_t * mbp,const char * s)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
mb_put_ustring(mbchain_t * mbp,const char * s)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
md_get_uint8(mdchain_t * mbp,uint8_t * x)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
md_get_uint16le(mdchain_t * mbp,uint16_t * x)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
md_get_uint16be(mdchain_t * mbp,uint16_t * x)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
md_get_uint32be(mdchain_t * mbp,uint32_t * x)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
md_get_uint32le(mdchain_t * mbp,uint32_t * x)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
md_get_uint64be(mdchain_t * mbp,uint64_t * x)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
md_get_uint64le(mdchain_t * mbp,uint64_t * x)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
md_get_mem(mdchain_t * mbp,void * vmem,int size,int type)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
md_get_mbuf(mdchain_t * mbp,int size,mbuf_t ** ret)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
md_get_string(mdchain_t * mbp,char ** str_pp,int uc)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
md_get_astring(mdchain_t * real_mbp,char ** str_pp)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
md_get_ustring(mdchain_t * real_mbp,char ** str_pp)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