187866Ssheldonh/*
287866Ssheldonh * Copyright (c) 2000, Boris Popov
387866Ssheldonh * All rights reserved.
487866Ssheldonh *
587866Ssheldonh * Redistribution and use in source and binary forms, with or without
687866Ssheldonh * modification, are permitted provided that the following conditions
787866Ssheldonh * are met:
887866Ssheldonh * 1. Redistributions of source code must retain the above copyright
987866Ssheldonh *    notice, this list of conditions and the following disclaimer.
1087866Ssheldonh * 2. Redistributions in binary form must reproduce the above copyright
1187866Ssheldonh *    notice, this list of conditions and the following disclaimer in the
1287866Ssheldonh *    documentation and/or other materials provided with the distribution.
1387866Ssheldonh * 3. All advertising materials mentioning features or use of this software
1487866Ssheldonh *    must display the following acknowledgement:
1587866Ssheldonh *    This product includes software developed by Boris Popov.
1687866Ssheldonh * 4. Neither the name of the author nor the names of any co-contributors
1787866Ssheldonh *    may be used to endorse or promote products derived from this software
1887866Ssheldonh *    without specific prior written permission.
1987866Ssheldonh *
2087866Ssheldonh * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
2187866Ssheldonh * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2287866Ssheldonh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2387866Ssheldonh * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
2487866Ssheldonh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2587866Ssheldonh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
2687866Ssheldonh * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2787866Ssheldonh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2887866Ssheldonh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2987866Ssheldonh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
3087866Ssheldonh * SUCH DAMAGE.
3187866Ssheldonh *
3287866Ssheldonh * $Id: mbuf.c,v 1.6 2001/02/24 15:56:04 bp Exp $
3387866Ssheldonh */
3487866Ssheldonh
35136700Sobrien#include <sys/cdefs.h>
36136700Sobrien__FBSDID("$FreeBSD$");
37136700Sobrien
3887866Ssheldonh#include <sys/types.h>
39150312Simura#include <sys/endian.h>
40136700Sobrien#include <arpa/inet.h>
4187866Ssheldonh#include <ctype.h>
4287866Ssheldonh#include <errno.h>
4387866Ssheldonh#include <stdio.h>
4487866Ssheldonh#include <stdlib.h>
4587866Ssheldonh#include <string.h>
4687866Ssheldonh
4787866Ssheldonh#include <netsmb/smb_lib.h>
4887866Ssheldonh
4987866Ssheldonh#define MBERROR(format, args...) printf("%s(%d): "format, __FUNCTION__ , \
5087866Ssheldonh				    __LINE__ ,## args)
5187866Ssheldonh
5287866Ssheldonhstatic int
5387866Ssheldonhm_get(size_t len, struct mbuf **mpp)
5487866Ssheldonh{
5587866Ssheldonh	struct mbuf *m;
5687866Ssheldonh
5787866Ssheldonh	len = M_ALIGN(len);
5887866Ssheldonh	if (len < M_MINSIZE)
5987866Ssheldonh		len = M_MINSIZE;
6087866Ssheldonh	m = malloc(M_BASESIZE + len);
6187866Ssheldonh	if (m == NULL)
6287866Ssheldonh		return ENOMEM;
6387866Ssheldonh	bzero(m, M_BASESIZE + len);
6487866Ssheldonh	m->m_maxlen = len;
6587866Ssheldonh	m->m_data = M_TOP(m);
6687866Ssheldonh	*mpp = m;
6787866Ssheldonh	return 0;
6887866Ssheldonh}
6987866Ssheldonh
7087866Ssheldonhstatic void
7187866Ssheldonhm_free(struct mbuf *m)
7287866Ssheldonh{
7387866Ssheldonh	free(m);
7487866Ssheldonh}
7587866Ssheldonh
7687866Ssheldonhstatic void
7787866Ssheldonhm_freem(struct mbuf *m0)
7887866Ssheldonh{
7987866Ssheldonh	struct mbuf *m;
8087866Ssheldonh
8187866Ssheldonh	while (m0) {
8287866Ssheldonh		m = m0->m_next;
8387866Ssheldonh		m_free(m0);
8487866Ssheldonh		m0 = m;
8587866Ssheldonh	}
8687866Ssheldonh}
8787866Ssheldonh
8887866Ssheldonhstatic size_t
8987866Ssheldonhm_totlen(struct mbuf *m0)
9087866Ssheldonh{
9187866Ssheldonh	struct mbuf *m = m0;
9287866Ssheldonh	int len = 0;
9387866Ssheldonh
9487866Ssheldonh	while (m) {
9587866Ssheldonh		len += m->m_len;
9687866Ssheldonh		m = m->m_next;
9787866Ssheldonh	}
9887866Ssheldonh	return len;
9987866Ssheldonh}
10087866Ssheldonh
10187866Ssheldonhint
10287866Ssheldonhm_lineup(struct mbuf *m0, struct mbuf **mpp)
10387866Ssheldonh{
10487866Ssheldonh	struct mbuf *nm, *m;
10587866Ssheldonh	char *dp;
10687866Ssheldonh	size_t len;
10787866Ssheldonh	int error;
10887866Ssheldonh
10987866Ssheldonh	if (m0->m_next == NULL) {
11087866Ssheldonh		*mpp = m0;
11187866Ssheldonh		return 0;
11287866Ssheldonh	}
11387866Ssheldonh	if ((error = m_get(m_totlen(m0), &nm)) != 0)
11487866Ssheldonh		return error;
11587866Ssheldonh	dp = mtod(nm, char *);
11687866Ssheldonh	while (m0) {
11787866Ssheldonh		len = m0->m_len;
11887866Ssheldonh		bcopy(m0->m_data, dp, len);
11987866Ssheldonh		dp += len;
12087866Ssheldonh		m = m0->m_next;
12187866Ssheldonh		m_free(m0);
12287866Ssheldonh		m0 = m;
12387866Ssheldonh	}
12487866Ssheldonh	*mpp = nm;
12587866Ssheldonh	return 0;
12687866Ssheldonh}
12787866Ssheldonh
12887866Ssheldonhint
12987866Ssheldonhmb_init(struct mbdata *mbp, size_t size)
13087866Ssheldonh{
13187866Ssheldonh	struct mbuf *m;
13287866Ssheldonh	int error;
13387866Ssheldonh
13487866Ssheldonh	if ((error = m_get(size, &m)) != 0)
13587866Ssheldonh		return error;
13687866Ssheldonh	return mb_initm(mbp, m);
13787866Ssheldonh}
13887866Ssheldonh
13987866Ssheldonhint
14087866Ssheldonhmb_initm(struct mbdata *mbp, struct mbuf *m)
14187866Ssheldonh{
14287866Ssheldonh	bzero(mbp, sizeof(*mbp));
14387866Ssheldonh	mbp->mb_top = mbp->mb_cur = m;
14487866Ssheldonh	mbp->mb_pos = mtod(m, char *);
14587866Ssheldonh	return 0;
14687866Ssheldonh}
14787866Ssheldonh
14887866Ssheldonhint
14987866Ssheldonhmb_done(struct mbdata *mbp)
15087866Ssheldonh{
15187866Ssheldonh	if (mbp->mb_top) {
15287866Ssheldonh		m_freem(mbp->mb_top);
15387866Ssheldonh		mbp->mb_top = NULL;
15487866Ssheldonh	}
15587866Ssheldonh	return 0;
15687866Ssheldonh}
15787866Ssheldonh
15887866Ssheldonh/*
15987866Ssheldonhint
16087866Ssheldonhmb_fixhdr(struct mbdata *mbp)
16187866Ssheldonh{
16287866Ssheldonh	struct mbuf *m = mbp->mb_top;
16387866Ssheldonh	int len = 0;
16487866Ssheldonh
16587866Ssheldonh	while (m) {
16687866Ssheldonh		len += m->m_len;
16787866Ssheldonh		m = m->m_next;
16887866Ssheldonh	}
16987866Ssheldonh	mbp->mb_top->m_pkthdr.len = len;
17087866Ssheldonh	return len;
17187866Ssheldonh}
17287866Ssheldonh*/
17387866Ssheldonhint
17487866Ssheldonhm_getm(struct mbuf *top, size_t len, struct mbuf **mpp)
17587866Ssheldonh{
17687866Ssheldonh	struct mbuf *m, *mp;
17787866Ssheldonh	int error;
17887866Ssheldonh
17987866Ssheldonh	for (mp = top; ; mp = mp->m_next) {
18087866Ssheldonh		len -= M_TRAILINGSPACE(mp);
18187866Ssheldonh		if (mp->m_next == NULL)
18287866Ssheldonh			break;
18387866Ssheldonh
18487866Ssheldonh	}
18587866Ssheldonh	if (len > 0) {
18687866Ssheldonh		if ((error = m_get(len, &m)) != 0)
18787866Ssheldonh			return error;
18887866Ssheldonh		mp->m_next = m;
18987866Ssheldonh	}
19087866Ssheldonh	*mpp = top;
19187866Ssheldonh	return 0;
19287866Ssheldonh}
19387866Ssheldonh
19487866Ssheldonh/*
19587866Ssheldonh * Routines to put data in a buffer
19687866Ssheldonh */
19787866Ssheldonh#define	MB_PUT(t)	int error; t *p; \
19887866Ssheldonh			if ((error = mb_fit(mbp, sizeof(t), (char**)&p)) != 0) \
19987866Ssheldonh				return error
20087866Ssheldonh
20187866Ssheldonh/*
20287866Ssheldonh * Check if object of size 'size' fit to the current position and
20387866Ssheldonh * allocate new mbuf if not. Advance pointers and increase length of mbuf(s).
20487866Ssheldonh * Return pointer to the object placeholder or NULL if any error occured.
20587866Ssheldonh */
20687866Ssheldonhint
20787866Ssheldonhmb_fit(struct mbdata *mbp, size_t size, char **pp)
20887866Ssheldonh{
20987866Ssheldonh	struct mbuf *m, *mn;
21087866Ssheldonh	int error;
21187866Ssheldonh
21287866Ssheldonh	m = mbp->mb_cur;
21387866Ssheldonh	if (M_TRAILINGSPACE(m) < (int)size) {
21487866Ssheldonh		if ((error = m_get(size, &mn)) != 0)
21587866Ssheldonh			return error;
21687866Ssheldonh		mbp->mb_pos = mtod(mn, char *);
21787866Ssheldonh		mbp->mb_cur = m->m_next = mn;
21887866Ssheldonh		m = mn;
21987866Ssheldonh	}
22087866Ssheldonh	m->m_len += size;
22187866Ssheldonh	*pp = mbp->mb_pos;
22287866Ssheldonh	mbp->mb_pos += size;
22387866Ssheldonh	mbp->mb_count += size;
22487866Ssheldonh	return 0;
22587866Ssheldonh}
22687866Ssheldonh
22787866Ssheldonhint
22887866Ssheldonhmb_put_uint8(struct mbdata *mbp, u_int8_t x)
22987866Ssheldonh{
23087866Ssheldonh	MB_PUT(u_int8_t);
23187866Ssheldonh	*p = x;
23287866Ssheldonh	return 0;
23387866Ssheldonh}
23487866Ssheldonh
23587866Ssheldonhint
23687866Ssheldonhmb_put_uint16be(struct mbdata *mbp, u_int16_t x)
23787866Ssheldonh{
23887866Ssheldonh	MB_PUT(u_int16_t);
23987866Ssheldonh	setwbe(p, 0, x);
24087866Ssheldonh	return 0;
24187866Ssheldonh}
24287866Ssheldonh
24387866Ssheldonhint
24487866Ssheldonhmb_put_uint16le(struct mbdata *mbp, u_int16_t x)
24587866Ssheldonh{
24687866Ssheldonh	MB_PUT(u_int16_t);
24787866Ssheldonh	setwle(p, 0, x);
24887866Ssheldonh	return 0;
24987866Ssheldonh}
25087866Ssheldonh
25187866Ssheldonhint
25287866Ssheldonhmb_put_uint32be(struct mbdata *mbp, u_int32_t x)
25387866Ssheldonh{
25487866Ssheldonh	MB_PUT(u_int32_t);
25587866Ssheldonh	setdbe(p, 0, x);
25687866Ssheldonh	return 0;
25787866Ssheldonh}
25887866Ssheldonh
25987866Ssheldonhint
26087866Ssheldonhmb_put_uint32le(struct mbdata *mbp, u_int32_t x)
26187866Ssheldonh{
26287866Ssheldonh	MB_PUT(u_int32_t);
26387866Ssheldonh	setdle(p, 0, x);
26487866Ssheldonh	return 0;
26587866Ssheldonh}
26687866Ssheldonh
26787866Ssheldonhint
26887866Ssheldonhmb_put_int64be(struct mbdata *mbp, int64_t x)
26987866Ssheldonh{
27087866Ssheldonh	MB_PUT(int64_t);
271150312Simura	*p = htobe64(x);
27287866Ssheldonh	return 0;
27387866Ssheldonh}
27487866Ssheldonh
27587866Ssheldonhint
27687866Ssheldonhmb_put_int64le(struct mbdata *mbp, int64_t x)
27787866Ssheldonh{
27887866Ssheldonh	MB_PUT(int64_t);
279150312Simura	*p = htole64(x);
28087866Ssheldonh	return 0;
28187866Ssheldonh}
28287866Ssheldonh
28387866Ssheldonhint
28487866Ssheldonhmb_put_mem(struct mbdata *mbp, const char *source, size_t size)
28587866Ssheldonh{
28687866Ssheldonh	struct mbuf *m;
28787866Ssheldonh	char * dst;
28887866Ssheldonh	size_t cplen;
28987866Ssheldonh	int error;
29087866Ssheldonh
29187866Ssheldonh	if (size == 0)
29287866Ssheldonh		return 0;
29387866Ssheldonh	m = mbp->mb_cur;
29487866Ssheldonh	if ((error = m_getm(m, size, &m)) != 0)
29587866Ssheldonh		return error;
29687866Ssheldonh	while (size > 0) {
29787866Ssheldonh		cplen = M_TRAILINGSPACE(m);
29887866Ssheldonh		if (cplen == 0) {
29987866Ssheldonh			m = m->m_next;
30087866Ssheldonh			continue;
30187866Ssheldonh		}
30287866Ssheldonh		if (cplen > size)
30387866Ssheldonh			cplen = size;
30487866Ssheldonh		dst = mtod(m, char *) + m->m_len;
30587866Ssheldonh		if (source) {
30687866Ssheldonh			bcopy(source, dst, cplen);
30787866Ssheldonh			source += cplen;
30887866Ssheldonh		} else
30987866Ssheldonh			bzero(dst, cplen);
31087866Ssheldonh		size -= cplen;
31187866Ssheldonh		m->m_len += cplen;
31287866Ssheldonh		mbp->mb_count += cplen;
31387866Ssheldonh	}
31487866Ssheldonh	mbp->mb_pos = mtod(m, char *) + m->m_len;
31587866Ssheldonh	mbp->mb_cur = m;
31687866Ssheldonh	return 0;
31787866Ssheldonh}
31887866Ssheldonh
31987866Ssheldonhint
32087866Ssheldonhmb_put_mbuf(struct mbdata *mbp, struct mbuf *m)
32187866Ssheldonh{
32287866Ssheldonh	mbp->mb_cur->m_next = m;
32387866Ssheldonh	while (m) {
32487866Ssheldonh		mbp->mb_count += m->m_len;
32587866Ssheldonh		if (m->m_next == NULL)
32687866Ssheldonh			break;
32787866Ssheldonh		m = m->m_next;
32887866Ssheldonh	}
32987866Ssheldonh	mbp->mb_pos = mtod(m, char *) + m->m_len;
33087866Ssheldonh	mbp->mb_cur = m;
33187866Ssheldonh	return 0;
33287866Ssheldonh}
33387866Ssheldonh
33487866Ssheldonhint
33587866Ssheldonhmb_put_pstring(struct mbdata *mbp, const char *s)
33687866Ssheldonh{
33787866Ssheldonh	int error, len = strlen(s);
33887866Ssheldonh
33987866Ssheldonh	if (len > 255) {
34087866Ssheldonh		len = 255;
34187866Ssheldonh	}
34287866Ssheldonh	if ((error = mb_put_uint8(mbp, len)) != 0)
34387866Ssheldonh		return error;
34487866Ssheldonh	return mb_put_mem(mbp, s, len);
34587866Ssheldonh}
34687866Ssheldonh
34787866Ssheldonh/*
34887866Ssheldonh * Routines for fetching data from an mbuf chain
34987866Ssheldonh */
35087866Ssheldonh#define mb_left(m,p)	(mtod(m, char *) + (m)->m_len - (p))
35187866Ssheldonh
35287866Ssheldonhint
35387866Ssheldonhmb_get_uint8(struct mbdata *mbp, u_int8_t *x)
35487866Ssheldonh{
35587866Ssheldonh	return mb_get_mem(mbp, x, 1);
35687866Ssheldonh}
35787866Ssheldonh
35887866Ssheldonhint
35987866Ssheldonhmb_get_uint16(struct mbdata *mbp, u_int16_t *x)
36087866Ssheldonh{
36187866Ssheldonh	return mb_get_mem(mbp, (char *)x, 2);
36287866Ssheldonh}
36387866Ssheldonh
36487866Ssheldonhint
36587866Ssheldonhmb_get_uint16le(struct mbdata *mbp, u_int16_t *x)
36687866Ssheldonh{
36787866Ssheldonh	u_int16_t v;
36887866Ssheldonh	int error = mb_get_uint16(mbp, &v);
36987866Ssheldonh
370150312Simura	*x = le16toh(v);
37187866Ssheldonh	return error;
37287866Ssheldonh}
37387866Ssheldonh
37487866Ssheldonhint
37587866Ssheldonhmb_get_uint16be(struct mbdata *mbp, u_int16_t *x) {
37687866Ssheldonh	u_int16_t v;
37787866Ssheldonh	int error = mb_get_uint16(mbp, &v);
37887866Ssheldonh
379150312Simura	*x = be16toh(v);
38087866Ssheldonh	return error;
38187866Ssheldonh}
38287866Ssheldonh
38387866Ssheldonhint
38487866Ssheldonhmb_get_uint32(struct mbdata *mbp, u_int32_t *x)
38587866Ssheldonh{
38687866Ssheldonh	return mb_get_mem(mbp, (char *)x, 4);
38787866Ssheldonh}
38887866Ssheldonh
38987866Ssheldonhint
39087866Ssheldonhmb_get_uint32be(struct mbdata *mbp, u_int32_t *x)
39187866Ssheldonh{
39287866Ssheldonh	u_int32_t v;
39387866Ssheldonh	int error;
39487866Ssheldonh
39587866Ssheldonh	error = mb_get_uint32(mbp, &v);
396150312Simura	*x = be32toh(v);
39787866Ssheldonh	return error;
39887866Ssheldonh}
39987866Ssheldonh
40087866Ssheldonhint
40187866Ssheldonhmb_get_uint32le(struct mbdata *mbp, u_int32_t *x)
40287866Ssheldonh{
40387866Ssheldonh	u_int32_t v;
40487866Ssheldonh	int error;
40587866Ssheldonh
40687866Ssheldonh	error = mb_get_uint32(mbp, &v);
407150312Simura	*x = le32toh(v);
40887866Ssheldonh	return error;
40987866Ssheldonh}
41087866Ssheldonh
41187866Ssheldonhint
41287866Ssheldonhmb_get_int64(struct mbdata *mbp, int64_t *x)
41387866Ssheldonh{
41487866Ssheldonh	return mb_get_mem(mbp, (char *)x, 8);
41587866Ssheldonh}
41687866Ssheldonh
41787866Ssheldonhint
41887866Ssheldonhmb_get_int64be(struct mbdata *mbp, int64_t *x)
41987866Ssheldonh{
42087866Ssheldonh	int64_t v;
42187866Ssheldonh	int error;
42287866Ssheldonh
42387866Ssheldonh	error = mb_get_int64(mbp, &v);
424150312Simura	*x = be64toh(v);
42587866Ssheldonh	return error;
42687866Ssheldonh}
42787866Ssheldonh
42887866Ssheldonhint
42987866Ssheldonhmb_get_int64le(struct mbdata *mbp, int64_t *x)
43087866Ssheldonh{
43187866Ssheldonh	int64_t v;
43287866Ssheldonh	int error;
43387866Ssheldonh
43487866Ssheldonh	error = mb_get_int64(mbp, &v);
435150312Simura	*x = le64toh(v);
43687866Ssheldonh	return error;
43787866Ssheldonh}
43887866Ssheldonh
43987866Ssheldonhint
44087866Ssheldonhmb_get_mem(struct mbdata *mbp, char * target, size_t size)
44187866Ssheldonh{
44287866Ssheldonh	struct mbuf *m = mbp->mb_cur;
44387866Ssheldonh	u_int count;
44487866Ssheldonh
44587866Ssheldonh	while (size > 0) {
44687866Ssheldonh		if (m == NULL) {
44787866Ssheldonh			MBERROR("incomplete copy\n");
44887866Ssheldonh			return EBADRPC;
44987866Ssheldonh		}
45087866Ssheldonh		count = mb_left(m, mbp->mb_pos);
45187866Ssheldonh		if (count == 0) {
45287866Ssheldonh			mbp->mb_cur = m = m->m_next;
45387866Ssheldonh			if (m)
45487866Ssheldonh				mbp->mb_pos = mtod(m, char *);
45587866Ssheldonh			continue;
45687866Ssheldonh		}
45787866Ssheldonh		if (count > size)
45887866Ssheldonh			count = size;
45987866Ssheldonh		size -= count;
46087866Ssheldonh		if (target) {
46187866Ssheldonh			if (count == 1) {
46287866Ssheldonh				*target++ = *mbp->mb_pos;
46387866Ssheldonh			} else {
46487866Ssheldonh				bcopy(mbp->mb_pos, target, count);
46587866Ssheldonh				target += count;
46687866Ssheldonh			}
46787866Ssheldonh		}
46887866Ssheldonh		mbp->mb_pos += count;
46987866Ssheldonh	}
47087866Ssheldonh	return 0;
47187866Ssheldonh}
472