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
m_get(size_t len,struct mbuf ** mpp)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
m_free(struct mbuf * m)71 m_free(struct mbuf *m)
72 {
73 free(m);
74 }
75
76 static void
m_freem(struct mbuf * m0)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
m_totlen(struct mbuf * m0)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
m_lineup(struct mbuf * m0,struct mbuf ** mpp)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
mb_init(struct mbdata * mbp,size_t size)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
mb_initm(struct mbdata * mbp,struct mbuf * m)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
mb_done(struct mbdata * mbp)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
m_getm(struct mbuf * top,size_t len,struct mbuf ** mpp)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
mb_fit(struct mbdata * mbp,size_t size,char ** pp)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
mb_put_uint8(struct mbdata * mbp,u_int8_t x)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
mb_put_uint16be(struct mbdata * mbp,u_int16_t x)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
mb_put_uint16le(struct mbdata * mbp,u_int16_t x)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
mb_put_uint32be(struct mbdata * mbp,u_int32_t x)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
mb_put_uint32le(struct mbdata * mbp,u_int32_t x)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
mb_put_int64be(struct mbdata * mbp,int64_t x)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
mb_put_int64le(struct mbdata * mbp,int64_t x)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
mb_put_mem(struct mbdata * mbp,const char * source,size_t size)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
mb_put_mbuf(struct mbdata * mbp,struct mbuf * m)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
mb_put_pstring(struct mbdata * mbp,const char * s)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
mb_get_uint8(struct mbdata * mbp,u_int8_t * x)353 mb_get_uint8(struct mbdata *mbp, u_int8_t *x)
354 {
355 return mb_get_mem(mbp, x, 1);
356 }
357
358 int
mb_get_uint16(struct mbdata * mbp,u_int16_t * x)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
mb_get_uint16le(struct mbdata * mbp,u_int16_t * x)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
mb_get_uint16be(struct mbdata * mbp,u_int16_t * x)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
mb_get_uint32(struct mbdata * mbp,u_int32_t * x)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
mb_get_uint32be(struct mbdata * mbp,u_int32_t * x)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
mb_get_uint32le(struct mbdata * mbp,u_int32_t * x)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
mb_get_int64(struct mbdata * mbp,int64_t * x)412 mb_get_int64(struct mbdata *mbp, int64_t *x)
413 {
414 return mb_get_mem(mbp, (char *)x, 8);
415 }
416
417 int
mb_get_int64be(struct mbdata * mbp,int64_t * x)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
mb_get_int64le(struct mbdata * mbp,int64_t * x)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
mb_get_mem(struct mbdata * mbp,char * target,size_t size)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