xref: /freebsd/contrib/smbfs/lib/smb/mbuf.c (revision 42249ef2)
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 
52 static int
53 m_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 
70 static void
71 m_free(struct mbuf *m)
72 {
73 	free(m);
74 }
75 
76 static void
77 m_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 
88 static size_t
89 m_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 
101 int
102 m_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 
128 int
129 mb_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 
139 int
140 mb_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 
148 int
149 mb_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 /*
159 int
160 mb_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 */
173 int
174 m_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  */
206 int
207 mb_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 
227 int
228 mb_put_uint8(struct mbdata *mbp, u_int8_t x)
229 {
230 	MB_PUT(u_int8_t);
231 	*p = x;
232 	return 0;
233 }
234 
235 int
236 mb_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 
243 int
244 mb_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 
251 int
252 mb_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 
259 int
260 mb_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 
267 int
268 mb_put_int64be(struct mbdata *mbp, int64_t x)
269 {
270 	MB_PUT(int64_t);
271 	*p = htobe64(x);
272 	return 0;
273 }
274 
275 int
276 mb_put_int64le(struct mbdata *mbp, int64_t x)
277 {
278 	MB_PUT(int64_t);
279 	*p = htole64(x);
280 	return 0;
281 }
282 
283 int
284 mb_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 
319 int
320 mb_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 
334 int
335 mb_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 
352 int
353 mb_get_uint8(struct mbdata *mbp, u_int8_t *x)
354 {
355 	return mb_get_mem(mbp, x, 1);
356 }
357 
358 int
359 mb_get_uint16(struct mbdata *mbp, u_int16_t *x)
360 {
361 	return mb_get_mem(mbp, (char *)x, 2);
362 }
363 
364 int
365 mb_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 
374 int
375 mb_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 
383 int
384 mb_get_uint32(struct mbdata *mbp, u_int32_t *x)
385 {
386 	return mb_get_mem(mbp, (char *)x, 4);
387 }
388 
389 int
390 mb_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 
400 int
401 mb_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 
411 int
412 mb_get_int64(struct mbdata *mbp, int64_t *x)
413 {
414 	return mb_get_mem(mbp, (char *)x, 8);
415 }
416 
417 int
418 mb_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 
428 int
429 mb_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 
439 int
440 mb_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