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