1/*
2 * Copyright (c) 2000, Boris Popov
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 * 1. Redistributions of source code must retain the above copyright
9 *    notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 *    notice, this list of conditions and the following disclaimer in the
12 *    documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 *    must display the following acknowledgement:
15 *    This product includes software developed by Boris Popov.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 *    may be used to endorse or promote products derived from this software
18 *    without specific prior written permission.
19 *
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 * SUCH DAMAGE.
31 *
32 * $Id: mbuf.c,v 1.6 2001/02/24 15:56:04 bp Exp $
33 */
34
35#include <sys/cdefs.h>
36__FBSDID("$FreeBSD$");
37
38#include <sys/types.h>
39#include <sys/endian.h>
40#include <arpa/inet.h>
41#include <ctype.h>
42#include <errno.h>
43#include <stdio.h>
44#include <stdlib.h>
45#include <string.h>
46
47#include <netsmb/smb_lib.h>
48
49#define MBERROR(format, args...) printf("%s(%d): "format, __FUNCTION__ , \
50				    __LINE__ ,## args)
51
52static int
53m_get(size_t len, struct mbuf **mpp)
54{
55	struct mbuf *m;
56
57	len = M_ALIGN(len);
58	if (len < M_MINSIZE)
59		len = M_MINSIZE;
60	m = malloc(M_BASESIZE + len);
61	if (m == NULL)
62		return ENOMEM;
63	bzero(m, M_BASESIZE + len);
64	m->m_maxlen = len;
65	m->m_data = M_TOP(m);
66	*mpp = m;
67	return 0;
68}
69
70static void
71m_free(struct mbuf *m)
72{
73	free(m);
74}
75
76static void
77m_freem(struct mbuf *m0)
78{
79	struct mbuf *m;
80
81	while (m0) {
82		m = m0->m_next;
83		m_free(m0);
84		m0 = m;
85	}
86}
87
88static size_t
89m_totlen(struct mbuf *m0)
90{
91	struct mbuf *m = m0;
92	int len = 0;
93
94	while (m) {
95		len += m->m_len;
96		m = m->m_next;
97	}
98	return len;
99}
100
101int
102m_lineup(struct mbuf *m0, struct mbuf **mpp)
103{
104	struct mbuf *nm, *m;
105	char *dp;
106	size_t len;
107	int error;
108
109	if (m0->m_next == NULL) {
110		*mpp = m0;
111		return 0;
112	}
113	if ((error = m_get(m_totlen(m0), &nm)) != 0)
114		return error;
115	dp = mtod(nm, char *);
116	while (m0) {
117		len = m0->m_len;
118		bcopy(m0->m_data, dp, len);
119		dp += len;
120		m = m0->m_next;
121		m_free(m0);
122		m0 = m;
123	}
124	*mpp = nm;
125	return 0;
126}
127
128int
129mb_init(struct mbdata *mbp, size_t size)
130{
131	struct mbuf *m;
132	int error;
133
134	if ((error = m_get(size, &m)) != 0)
135		return error;
136	return mb_initm(mbp, m);
137}
138
139int
140mb_initm(struct mbdata *mbp, struct mbuf *m)
141{
142	bzero(mbp, sizeof(*mbp));
143	mbp->mb_top = mbp->mb_cur = m;
144	mbp->mb_pos = mtod(m, char *);
145	return 0;
146}
147
148int
149mb_done(struct mbdata *mbp)
150{
151	if (mbp->mb_top) {
152		m_freem(mbp->mb_top);
153		mbp->mb_top = NULL;
154	}
155	return 0;
156}
157
158/*
159int
160mb_fixhdr(struct mbdata *mbp)
161{
162	struct mbuf *m = mbp->mb_top;
163	int len = 0;
164
165	while (m) {
166		len += m->m_len;
167		m = m->m_next;
168	}
169	mbp->mb_top->m_pkthdr.len = len;
170	return len;
171}
172*/
173int
174m_getm(struct mbuf *top, size_t len, struct mbuf **mpp)
175{
176	struct mbuf *m, *mp;
177	int error;
178
179	for (mp = top; ; mp = mp->m_next) {
180		len -= M_TRAILINGSPACE(mp);
181		if (mp->m_next == NULL)
182			break;
183
184	}
185	if (len > 0) {
186		if ((error = m_get(len, &m)) != 0)
187			return error;
188		mp->m_next = m;
189	}
190	*mpp = top;
191	return 0;
192}
193
194/*
195 * Routines to put data in a buffer
196 */
197#define	MB_PUT(t)	int error; t *p; \
198			if ((error = mb_fit(mbp, sizeof(t), (char**)&p)) != 0) \
199				return error
200
201/*
202 * Check if object of size 'size' fit to the current position and
203 * allocate new mbuf if not. Advance pointers and increase length of mbuf(s).
204 * Return pointer to the object placeholder or NULL if any error occured.
205 */
206int
207mb_fit(struct mbdata *mbp, size_t size, char **pp)
208{
209	struct mbuf *m, *mn;
210	int error;
211
212	m = mbp->mb_cur;
213	if (M_TRAILINGSPACE(m) < (int)size) {
214		if ((error = m_get(size, &mn)) != 0)
215			return error;
216		mbp->mb_pos = mtod(mn, char *);
217		mbp->mb_cur = m->m_next = mn;
218		m = mn;
219	}
220	m->m_len += size;
221	*pp = mbp->mb_pos;
222	mbp->mb_pos += size;
223	mbp->mb_count += size;
224	return 0;
225}
226
227int
228mb_put_uint8(struct mbdata *mbp, u_int8_t x)
229{
230	MB_PUT(u_int8_t);
231	*p = x;
232	return 0;
233}
234
235int
236mb_put_uint16be(struct mbdata *mbp, u_int16_t x)
237{
238	MB_PUT(u_int16_t);
239	setwbe(p, 0, x);
240	return 0;
241}
242
243int
244mb_put_uint16le(struct mbdata *mbp, u_int16_t x)
245{
246	MB_PUT(u_int16_t);
247	setwle(p, 0, x);
248	return 0;
249}
250
251int
252mb_put_uint32be(struct mbdata *mbp, u_int32_t x)
253{
254	MB_PUT(u_int32_t);
255	setdbe(p, 0, x);
256	return 0;
257}
258
259int
260mb_put_uint32le(struct mbdata *mbp, u_int32_t x)
261{
262	MB_PUT(u_int32_t);
263	setdle(p, 0, x);
264	return 0;
265}
266
267int
268mb_put_int64be(struct mbdata *mbp, int64_t x)
269{
270	MB_PUT(int64_t);
271	*p = htobe64(x);
272	return 0;
273}
274
275int
276mb_put_int64le(struct mbdata *mbp, int64_t x)
277{
278	MB_PUT(int64_t);
279	*p = htole64(x);
280	return 0;
281}
282
283int
284mb_put_mem(struct mbdata *mbp, const char *source, size_t size)
285{
286	struct mbuf *m;
287	char * dst;
288	size_t cplen;
289	int error;
290
291	if (size == 0)
292		return 0;
293	m = mbp->mb_cur;
294	if ((error = m_getm(m, size, &m)) != 0)
295		return error;
296	while (size > 0) {
297		cplen = M_TRAILINGSPACE(m);
298		if (cplen == 0) {
299			m = m->m_next;
300			continue;
301		}
302		if (cplen > size)
303			cplen = size;
304		dst = mtod(m, char *) + m->m_len;
305		if (source) {
306			bcopy(source, dst, cplen);
307			source += cplen;
308		} else
309			bzero(dst, cplen);
310		size -= cplen;
311		m->m_len += cplen;
312		mbp->mb_count += cplen;
313	}
314	mbp->mb_pos = mtod(m, char *) + m->m_len;
315	mbp->mb_cur = m;
316	return 0;
317}
318
319int
320mb_put_mbuf(struct mbdata *mbp, struct mbuf *m)
321{
322	mbp->mb_cur->m_next = m;
323	while (m) {
324		mbp->mb_count += m->m_len;
325		if (m->m_next == NULL)
326			break;
327		m = m->m_next;
328	}
329	mbp->mb_pos = mtod(m, char *) + m->m_len;
330	mbp->mb_cur = m;
331	return 0;
332}
333
334int
335mb_put_pstring(struct mbdata *mbp, const char *s)
336{
337	int error, len = strlen(s);
338
339	if (len > 255) {
340		len = 255;
341	}
342	if ((error = mb_put_uint8(mbp, len)) != 0)
343		return error;
344	return mb_put_mem(mbp, s, len);
345}
346
347/*
348 * Routines for fetching data from an mbuf chain
349 */
350#define mb_left(m,p)	(mtod(m, char *) + (m)->m_len - (p))
351
352int
353mb_get_uint8(struct mbdata *mbp, u_int8_t *x)
354{
355	return mb_get_mem(mbp, x, 1);
356}
357
358int
359mb_get_uint16(struct mbdata *mbp, u_int16_t *x)
360{
361	return mb_get_mem(mbp, (char *)x, 2);
362}
363
364int
365mb_get_uint16le(struct mbdata *mbp, u_int16_t *x)
366{
367	u_int16_t v;
368	int error = mb_get_uint16(mbp, &v);
369
370	*x = le16toh(v);
371	return error;
372}
373
374int
375mb_get_uint16be(struct mbdata *mbp, u_int16_t *x) {
376	u_int16_t v;
377	int error = mb_get_uint16(mbp, &v);
378
379	*x = be16toh(v);
380	return error;
381}
382
383int
384mb_get_uint32(struct mbdata *mbp, u_int32_t *x)
385{
386	return mb_get_mem(mbp, (char *)x, 4);
387}
388
389int
390mb_get_uint32be(struct mbdata *mbp, u_int32_t *x)
391{
392	u_int32_t v;
393	int error;
394
395	error = mb_get_uint32(mbp, &v);
396	*x = be32toh(v);
397	return error;
398}
399
400int
401mb_get_uint32le(struct mbdata *mbp, u_int32_t *x)
402{
403	u_int32_t v;
404	int error;
405
406	error = mb_get_uint32(mbp, &v);
407	*x = le32toh(v);
408	return error;
409}
410
411int
412mb_get_int64(struct mbdata *mbp, int64_t *x)
413{
414	return mb_get_mem(mbp, (char *)x, 8);
415}
416
417int
418mb_get_int64be(struct mbdata *mbp, int64_t *x)
419{
420	int64_t v;
421	int error;
422
423	error = mb_get_int64(mbp, &v);
424	*x = be64toh(v);
425	return error;
426}
427
428int
429mb_get_int64le(struct mbdata *mbp, int64_t *x)
430{
431	int64_t v;
432	int error;
433
434	error = mb_get_int64(mbp, &v);
435	*x = le64toh(v);
436	return error;
437}
438
439int
440mb_get_mem(struct mbdata *mbp, char * target, size_t size)
441{
442	struct mbuf *m = mbp->mb_cur;
443	u_int count;
444
445	while (size > 0) {
446		if (m == NULL) {
447			MBERROR("incomplete copy\n");
448			return EBADRPC;
449		}
450		count = mb_left(m, mbp->mb_pos);
451		if (count == 0) {
452			mbp->mb_cur = m = m->m_next;
453			if (m)
454				mbp->mb_pos = mtod(m, char *);
455			continue;
456		}
457		if (count > size)
458			count = size;
459		size -= count;
460		if (target) {
461			if (count == 1) {
462				*target++ = *mbp->mb_pos;
463			} else {
464				bcopy(mbp->mb_pos, target, count);
465				target += count;
466			}
467		}
468		mbp->mb_pos += count;
469	}
470	return 0;
471}
472