xref: /freebsd/contrib/smbfs/lib/smb/mbuf.c (revision c19fb1f963e3dc88a82b20d1b17f94a4cd321e74)
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/types.h>
36 #include <sys/endian.h>
37 #include <arpa/inet.h>
38 #include <ctype.h>
39 #include <errno.h>
40 #include <stdio.h>
41 #include <stdlib.h>
42 #include <string.h>
43 
44 #include <netsmb/smb_lib.h>
45 
46 #define MBERROR(format, args...) printf("%s(%d): "format, __FUNCTION__ , \
47 				    __LINE__ ,## args)
48 
49 static int
50 m_get(size_t len, struct mbuf **mpp)
51 {
52 	struct mbuf *m;
53 
54 	len = M_ALIGN(len);
55 	if (len < M_MINSIZE)
56 		len = M_MINSIZE;
57 	m = malloc(M_BASESIZE + len);
58 	if (m == NULL)
59 		return ENOMEM;
60 	bzero(m, M_BASESIZE + len);
61 	m->m_maxlen = len;
62 	m->m_data = M_TOP(m);
63 	*mpp = m;
64 	return 0;
65 }
66 
67 static void
68 m_free(struct mbuf *m)
69 {
70 	free(m);
71 }
72 
73 static void
74 m_freem(struct mbuf *m0)
75 {
76 	struct mbuf *m;
77 
78 	while (m0) {
79 		m = m0->m_next;
80 		m_free(m0);
81 		m0 = m;
82 	}
83 }
84 
85 static size_t
86 m_totlen(struct mbuf *m0)
87 {
88 	struct mbuf *m = m0;
89 	int len = 0;
90 
91 	while (m) {
92 		len += m->m_len;
93 		m = m->m_next;
94 	}
95 	return len;
96 }
97 
98 int
99 m_lineup(struct mbuf *m0, struct mbuf **mpp)
100 {
101 	struct mbuf *nm, *m;
102 	char *dp;
103 	size_t len;
104 	int error;
105 
106 	if (m0->m_next == NULL) {
107 		*mpp = m0;
108 		return 0;
109 	}
110 	if ((error = m_get(m_totlen(m0), &nm)) != 0)
111 		return error;
112 	dp = mtod(nm, char *);
113 	while (m0) {
114 		len = m0->m_len;
115 		bcopy(m0->m_data, dp, len);
116 		dp += len;
117 		m = m0->m_next;
118 		m_free(m0);
119 		m0 = m;
120 	}
121 	*mpp = nm;
122 	return 0;
123 }
124 
125 int
126 mb_init(struct mbdata *mbp, size_t size)
127 {
128 	struct mbuf *m;
129 	int error;
130 
131 	if ((error = m_get(size, &m)) != 0)
132 		return error;
133 	return mb_initm(mbp, m);
134 }
135 
136 int
137 mb_initm(struct mbdata *mbp, struct mbuf *m)
138 {
139 	bzero(mbp, sizeof(*mbp));
140 	mbp->mb_top = mbp->mb_cur = m;
141 	mbp->mb_pos = mtod(m, char *);
142 	return 0;
143 }
144 
145 int
146 mb_done(struct mbdata *mbp)
147 {
148 	if (mbp->mb_top) {
149 		m_freem(mbp->mb_top);
150 		mbp->mb_top = NULL;
151 	}
152 	return 0;
153 }
154 
155 /*
156 int
157 mb_fixhdr(struct mbdata *mbp)
158 {
159 	struct mbuf *m = mbp->mb_top;
160 	int len = 0;
161 
162 	while (m) {
163 		len += m->m_len;
164 		m = m->m_next;
165 	}
166 	mbp->mb_top->m_pkthdr.len = len;
167 	return len;
168 }
169 */
170 int
171 m_getm(struct mbuf *top, size_t len, struct mbuf **mpp)
172 {
173 	struct mbuf *m, *mp;
174 	int error;
175 
176 	for (mp = top; ; mp = mp->m_next) {
177 		len -= M_TRAILINGSPACE(mp);
178 		if (mp->m_next == NULL)
179 			break;
180 
181 	}
182 	if (len > 0) {
183 		if ((error = m_get(len, &m)) != 0)
184 			return error;
185 		mp->m_next = m;
186 	}
187 	*mpp = top;
188 	return 0;
189 }
190 
191 /*
192  * Routines to put data in a buffer
193  */
194 #define	MB_PUT(t)	int error; t *p; \
195 			if ((error = mb_fit(mbp, sizeof(t), (char**)&p)) != 0) \
196 				return error
197 
198 /*
199  * Check if object of size 'size' fit to the current position and
200  * allocate new mbuf if not. Advance pointers and increase length of mbuf(s).
201  * Return pointer to the object placeholder or NULL if any error occured.
202  */
203 int
204 mb_fit(struct mbdata *mbp, size_t size, char **pp)
205 {
206 	struct mbuf *m, *mn;
207 	int error;
208 
209 	m = mbp->mb_cur;
210 	if (M_TRAILINGSPACE(m) < (int)size) {
211 		if ((error = m_get(size, &mn)) != 0)
212 			return error;
213 		mbp->mb_pos = mtod(mn, char *);
214 		mbp->mb_cur = m->m_next = mn;
215 		m = mn;
216 	}
217 	m->m_len += size;
218 	*pp = mbp->mb_pos;
219 	mbp->mb_pos += size;
220 	mbp->mb_count += size;
221 	return 0;
222 }
223 
224 int
225 mb_put_uint8(struct mbdata *mbp, u_int8_t x)
226 {
227 	MB_PUT(u_int8_t);
228 	*p = x;
229 	return 0;
230 }
231 
232 int
233 mb_put_uint16be(struct mbdata *mbp, u_int16_t x)
234 {
235 	MB_PUT(u_int16_t);
236 	setwbe(p, 0, x);
237 	return 0;
238 }
239 
240 int
241 mb_put_uint16le(struct mbdata *mbp, u_int16_t x)
242 {
243 	MB_PUT(u_int16_t);
244 	setwle(p, 0, x);
245 	return 0;
246 }
247 
248 int
249 mb_put_uint32be(struct mbdata *mbp, u_int32_t x)
250 {
251 	MB_PUT(u_int32_t);
252 	setdbe(p, 0, x);
253 	return 0;
254 }
255 
256 int
257 mb_put_uint32le(struct mbdata *mbp, u_int32_t x)
258 {
259 	MB_PUT(u_int32_t);
260 	setdle(p, 0, x);
261 	return 0;
262 }
263 
264 int
265 mb_put_int64be(struct mbdata *mbp, int64_t x)
266 {
267 	MB_PUT(int64_t);
268 	*p = htobe64(x);
269 	return 0;
270 }
271 
272 int
273 mb_put_int64le(struct mbdata *mbp, int64_t x)
274 {
275 	MB_PUT(int64_t);
276 	*p = htole64(x);
277 	return 0;
278 }
279 
280 int
281 mb_put_mem(struct mbdata *mbp, const char *source, size_t size)
282 {
283 	struct mbuf *m;
284 	char * dst;
285 	size_t cplen;
286 	int error;
287 
288 	if (size == 0)
289 		return 0;
290 	m = mbp->mb_cur;
291 	if ((error = m_getm(m, size, &m)) != 0)
292 		return error;
293 	while (size > 0) {
294 		cplen = M_TRAILINGSPACE(m);
295 		if (cplen == 0) {
296 			m = m->m_next;
297 			continue;
298 		}
299 		if (cplen > size)
300 			cplen = size;
301 		dst = mtod(m, char *) + m->m_len;
302 		if (source) {
303 			bcopy(source, dst, cplen);
304 			source += cplen;
305 		} else
306 			bzero(dst, cplen);
307 		size -= cplen;
308 		m->m_len += cplen;
309 		mbp->mb_count += cplen;
310 	}
311 	mbp->mb_pos = mtod(m, char *) + m->m_len;
312 	mbp->mb_cur = m;
313 	return 0;
314 }
315 
316 int
317 mb_put_mbuf(struct mbdata *mbp, struct mbuf *m)
318 {
319 	mbp->mb_cur->m_next = m;
320 	while (m) {
321 		mbp->mb_count += m->m_len;
322 		if (m->m_next == NULL)
323 			break;
324 		m = m->m_next;
325 	}
326 	mbp->mb_pos = mtod(m, char *) + m->m_len;
327 	mbp->mb_cur = m;
328 	return 0;
329 }
330 
331 int
332 mb_put_pstring(struct mbdata *mbp, const char *s)
333 {
334 	int error, len = strlen(s);
335 
336 	if (len > 255) {
337 		len = 255;
338 	}
339 	if ((error = mb_put_uint8(mbp, len)) != 0)
340 		return error;
341 	return mb_put_mem(mbp, s, len);
342 }
343 
344 /*
345  * Routines for fetching data from an mbuf chain
346  */
347 #define mb_left(m,p)	(mtod(m, char *) + (m)->m_len - (p))
348 
349 int
350 mb_get_uint8(struct mbdata *mbp, u_int8_t *x)
351 {
352 	return mb_get_mem(mbp, x, 1);
353 }
354 
355 int
356 mb_get_uint16(struct mbdata *mbp, u_int16_t *x)
357 {
358 	return mb_get_mem(mbp, (char *)x, 2);
359 }
360 
361 int
362 mb_get_uint16le(struct mbdata *mbp, u_int16_t *x)
363 {
364 	u_int16_t v;
365 	int error = mb_get_uint16(mbp, &v);
366 
367 	*x = le16toh(v);
368 	return error;
369 }
370 
371 int
372 mb_get_uint16be(struct mbdata *mbp, u_int16_t *x) {
373 	u_int16_t v;
374 	int error = mb_get_uint16(mbp, &v);
375 
376 	*x = be16toh(v);
377 	return error;
378 }
379 
380 int
381 mb_get_uint32(struct mbdata *mbp, u_int32_t *x)
382 {
383 	return mb_get_mem(mbp, (char *)x, 4);
384 }
385 
386 int
387 mb_get_uint32be(struct mbdata *mbp, u_int32_t *x)
388 {
389 	u_int32_t v;
390 	int error;
391 
392 	error = mb_get_uint32(mbp, &v);
393 	*x = be32toh(v);
394 	return error;
395 }
396 
397 int
398 mb_get_uint32le(struct mbdata *mbp, u_int32_t *x)
399 {
400 	u_int32_t v;
401 	int error;
402 
403 	error = mb_get_uint32(mbp, &v);
404 	*x = le32toh(v);
405 	return error;
406 }
407 
408 int
409 mb_get_int64(struct mbdata *mbp, int64_t *x)
410 {
411 	return mb_get_mem(mbp, (char *)x, 8);
412 }
413 
414 int
415 mb_get_int64be(struct mbdata *mbp, int64_t *x)
416 {
417 	int64_t v;
418 	int error;
419 
420 	error = mb_get_int64(mbp, &v);
421 	*x = be64toh(v);
422 	return error;
423 }
424 
425 int
426 mb_get_int64le(struct mbdata *mbp, int64_t *x)
427 {
428 	int64_t v;
429 	int error;
430 
431 	error = mb_get_int64(mbp, &v);
432 	*x = le64toh(v);
433 	return error;
434 }
435 
436 int
437 mb_get_mem(struct mbdata *mbp, char * target, size_t size)
438 {
439 	struct mbuf *m = mbp->mb_cur;
440 	u_int count;
441 
442 	while (size > 0) {
443 		if (m == NULL) {
444 			MBERROR("incomplete copy\n");
445 			return EBADRPC;
446 		}
447 		count = mb_left(m, mbp->mb_pos);
448 		if (count == 0) {
449 			mbp->mb_cur = m = m->m_next;
450 			if (m)
451 				mbp->mb_pos = mtod(m, char *);
452 			continue;
453 		}
454 		if (count > size)
455 			count = size;
456 		size -= count;
457 		if (target) {
458 			if (count == 1) {
459 				*target++ = *mbp->mb_pos;
460 			} else {
461 				bcopy(mbp->mb_pos, target, count);
462 				target += count;
463 			}
464 		}
465 		mbp->mb_pos += count;
466 	}
467 	return 0;
468 }
469