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