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