Unbreak buildworld.
[dragonfly.git] / contrib / smbfs / lib / smb / mbuf.c
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 <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 = htobe64(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 = htole64(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         if (x != NULL)
367                 *x = le16toh(v);
368         return error;
369 }
370
371 int
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         if (x != NULL)
377                 *x = be16toh(v);
378         return error;
379 }
380
381 int
382 mb_get_uint32(struct mbdata *mbp, u_int32_t *x)
383 {
384         return mb_get_mem(mbp, (char *)x, 4);
385 }
386
387 int
388 mb_get_uint32be(struct mbdata *mbp, u_int32_t *x)
389 {
390         u_int32_t v;
391         int error;
392
393         error = mb_get_uint32(mbp, &v);
394         if (x != NULL)
395                 *x = be32toh(v);
396         return error;
397 }
398
399 int
400 mb_get_uint32le(struct mbdata *mbp, u_int32_t *x)
401 {
402         u_int32_t v;
403         int error;
404
405         error = mb_get_uint32(mbp, &v);
406         if (x != NULL)
407                 *x = le32toh(v);
408         return error;
409 }
410
411 int
412 mb_get_int64(struct mbdata *mbp, int64_t *x)
413 {
414         return mb_get_mem(mbp, (char *)x, 8);
415 }
416
417 int
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         if (x != NULL)
425                 *x = be64toh(v);
426         return error;
427 }
428
429 int
430 mb_get_int64le(struct mbdata *mbp, int64_t *x)
431 {
432         int64_t v;
433         int error;
434
435         error = mb_get_int64(mbp, &v);
436         if (x != NULL)
437                 *x = le64toh(v);
438         return error;
439 }
440
441 int
442 mb_get_mem(struct mbdata *mbp, char * target, size_t size)
443 {
444         struct mbuf *m = mbp->mb_cur;
445         u_int count;
446         
447         while (size > 0) {
448                 if (m == NULL) {
449                         MBERROR("incomplete copy\n");
450                         return EBADRPC;
451                 }
452                 count = mb_left(m, mbp->mb_pos);
453                 if (count == 0) {
454                         mbp->mb_cur = m = m->m_next;
455                         if (m)
456                                 mbp->mb_pos = mtod(m, char *);
457                         continue;
458                 }
459                 if (count > size)
460                         count = size;
461                 size -= count;
462                 if (target) {
463                         if (count == 1) {
464                                 *target++ = *mbp->mb_pos;
465                         } else {
466                                 bcopy(mbp->mb_pos, target, count);
467                                 target += count;
468                         }
469                 }
470                 mbp->mb_pos += count;
471         }
472         return 0;
473 }