Merge from vendor branch OPENSSH:
[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/mchain.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 = htobeq(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 = htoleq(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         *x = letohs(v);
367         return error;
368 }
369
370 int
371 mb_get_uint16be(struct mbdata *mbp, u_int16_t *x) {
372         u_int16_t v;
373         int error = mb_get_uint16(mbp, &v);
374
375         *x = betohs(v);
376         return error;
377 }
378
379 int
380 mb_get_uint32(struct mbdata *mbp, u_int32_t *x)
381 {
382         return mb_get_mem(mbp, (char *)x, 4);
383 }
384
385 int
386 mb_get_uint32be(struct mbdata *mbp, u_int32_t *x)
387 {
388         u_int32_t v;
389         int error;
390
391         error = mb_get_uint32(mbp, &v);
392         *x = betohl(v);
393         return error;
394 }
395
396 int
397 mb_get_uint32le(struct mbdata *mbp, u_int32_t *x)
398 {
399         u_int32_t v;
400         int error;
401
402         error = mb_get_uint32(mbp, &v);
403         *x = letohl(v);
404         return error;
405 }
406
407 int
408 mb_get_int64(struct mbdata *mbp, int64_t *x)
409 {
410         return mb_get_mem(mbp, (char *)x, 8);
411 }
412
413 int
414 mb_get_int64be(struct mbdata *mbp, int64_t *x)
415 {
416         int64_t v;
417         int error;
418
419         error = mb_get_int64(mbp, &v);
420         *x = betohq(v);
421         return error;
422 }
423
424 int
425 mb_get_int64le(struct mbdata *mbp, int64_t *x)
426 {
427         int64_t v;
428         int error;
429
430         error = mb_get_int64(mbp, &v);
431         *x = letohq(v);
432         return error;
433 }
434
435 int
436 mb_get_mem(struct mbdata *mbp, char * target, size_t size)
437 {
438         struct mbuf *m = mbp->mb_cur;
439         u_int count;
440         
441         while (size > 0) {
442                 if (m == NULL) {
443                         MBERROR("incomplete copy\n");
444                         return EBADRPC;
445                 }
446                 count = mb_left(m, mbp->mb_pos);
447                 if (count == 0) {
448                         mbp->mb_cur = m = m->m_next;
449                         if (m)
450                                 mbp->mb_pos = mtod(m, char *);
451                         continue;
452                 }
453                 if (count > size)
454                         count = size;
455                 size -= count;
456                 if (target) {
457                         if (count == 1) {
458                                 *target++ = *mbp->mb_pos;
459                         } else {
460                                 bcopy(mbp->mb_pos, target, count);
461                                 target += count;
462                         }
463                 }
464                 mbp->mb_pos += count;
465         }
466         return 0;
467 }