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