No empty .Rs/.Re
[netbsd-mini2440.git] / sys / netsmb / subr_mchain.c
blobb220863c8fd0c2200f5df42c76f9781fc66b40fa
1 /* $NetBSD: subr_mchain.c,v 1.17 2009/03/18 17:06:53 cegger Exp $ */
3 /*
4 * Copyright (c) 2000, 2001 Boris Popov
5 * All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Boris Popov.
18 * 4. Neither the name of the author nor the names of any co-contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * SUCH DAMAGE.
34 * FreeBSD: src/sys/kern/subr_mchain.c,v 1.4 2002/02/21 16:23:38 bp Exp
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: subr_mchain.c,v 1.17 2009/03/18 17:06:53 cegger Exp $");
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/errno.h>
43 #include <sys/mbuf.h>
44 #include <sys/uio.h>
46 #include <uvm/uvm_extern.h>
48 #include <netsmb/mchain.h>
50 #define MBERROR(x) aprint_error x
51 #define MBPANIC(x) aprint_error x
53 #ifdef __NetBSD__
54 static struct mbuf *
55 m_getm(struct mbuf *m, int len, int how, int type)
57 struct mbuf *top, *tail, *mp, *mtail = NULL;
59 KASSERT(len >= 0);
61 mp = m_get(how, type);
62 if (mp == NULL)
63 return (NULL);
64 else if (len > MINCLSIZE) {
65 m_clget(mp, how);
66 if ((mp->m_flags & M_EXT) == 0) {
67 m_free(mp);
68 return (NULL);
71 mp->m_len = 0;
72 len -= M_TRAILINGSPACE(mp);
74 if (m != NULL)
75 for (mtail = m; mtail->m_next != NULL; mtail = mtail->m_next);
76 else
77 m = mp;
79 top = tail = mp;
80 while (len > 0) {
81 mp = m_get(how, type);
82 if (mp == NULL)
83 goto failed;
85 tail->m_next = mp;
86 tail = mp;
87 if (len > MINCLSIZE) {
88 m_clget(mp, how);
89 if ((mp->m_flags & M_EXT) == 0)
90 goto failed;
93 mp->m_len = 0;
94 len -= M_TRAILINGSPACE(mp);
97 if (mtail != NULL)
98 mtail->m_next = top;
99 return (m);
101 failed:
102 m_freem(top);
103 return (NULL);
106 #endif /* __NetBSD__ */
109 * Various helper functions
112 m_fixhdr(struct mbuf *m0)
114 struct mbuf *m = m0;
115 int len = 0;
117 while (m) {
118 len += m->m_len;
119 m = m->m_next;
121 m0->m_pkthdr.len = len;
122 return len;
126 mb_init(struct mbchain *mbp)
128 struct mbuf *m;
130 m = m_gethdr(M_WAIT, MT_DATA);
131 if (m == NULL)
132 return ENOBUFS;
133 m->m_len = 0;
134 mb_initm(mbp, m);
135 return 0;
138 void
139 mb_initm(struct mbchain *mbp, struct mbuf *m)
141 memset(mbp, 0, sizeof(*mbp));
142 mbp->mb_top = mbp->mb_cur = m;
143 mbp->mb_mleft = M_TRAILINGSPACE(m);
146 void
147 mb_done(struct mbchain *mbp)
149 if (mbp->mb_top) {
150 m_freem(mbp->mb_top);
151 mbp->mb_top = NULL;
155 struct mbuf *
156 mb_detach(struct mbchain *mbp)
158 struct mbuf *m;
160 m = mbp->mb_top;
161 mbp->mb_top = NULL;
162 return m;
166 mb_fixhdr(struct mbchain *mbp)
168 return mbp->mb_top->m_pkthdr.len = m_fixhdr(mbp->mb_top);
172 * Check if object of size 'size' fit to the current position and
173 * allocate new mbuf if not. Advance pointers and increase length of mbuf(s).
174 * Return pointer to the object placeholder or NULL if any error occurred.
175 * Note: size should be <= MLEN
177 void *
178 mb_reserve(struct mbchain *mbp, int size)
180 struct mbuf *m, *mn;
181 void *bpos;
183 if (size > MLEN)
184 panic("mb_reserve: size = %d", size);
185 m = mbp->mb_cur;
186 if (mbp->mb_mleft < size) {
187 mn = m_get(M_WAIT, MT_DATA);
188 if (mn == NULL)
189 return NULL;
190 mbp->mb_cur = m->m_next = mn;
191 m = mn;
192 m->m_len = 0;
193 mbp->mb_mleft = M_TRAILINGSPACE(m);
195 mbp->mb_mleft -= size;
196 mbp->mb_count += size;
197 bpos = mtod(m, char *) + m->m_len;
198 m->m_len += size;
199 return bpos;
203 mb_put_uint8(struct mbchain *mbp, u_int8_t x)
205 return mb_put_mem(mbp, (void *)&x, sizeof(x), MB_MSYSTEM);
209 mb_put_uint16be(struct mbchain *mbp, u_int16_t x)
211 x = htobe16(x);
212 return mb_put_mem(mbp, (void *)&x, sizeof(x), MB_MSYSTEM);
216 mb_put_uint16le(struct mbchain *mbp, u_int16_t x)
218 x = htole16(x);
219 return mb_put_mem(mbp, (void *)&x, sizeof(x), MB_MSYSTEM);
223 mb_put_uint32be(struct mbchain *mbp, u_int32_t x)
225 x = htobe32(x);
226 return mb_put_mem(mbp, (void *)&x, sizeof(x), MB_MSYSTEM);
230 mb_put_uint32le(struct mbchain *mbp, u_int32_t x)
232 x = htole32(x);
233 return mb_put_mem(mbp, (void *)&x, sizeof(x), MB_MSYSTEM);
237 mb_put_int64be(struct mbchain *mbp, int64_t x)
239 x = htobe64(x);
240 return mb_put_mem(mbp, (void *)&x, sizeof(x), MB_MSYSTEM);
244 mb_put_int64le(struct mbchain *mbp, int64_t x)
246 x = htole64(x);
247 return mb_put_mem(mbp, (void *)&x, sizeof(x), MB_MSYSTEM);
251 mb_put_mem(struct mbchain *mbp, const char *source, int size, int type)
253 struct mbuf *m;
254 char *dst;
255 const char *src;
256 int cplen, error, mleft, count;
258 m = mbp->mb_cur;
259 mleft = mbp->mb_mleft;
261 while (size > 0) {
262 if (mleft == 0) {
263 if (m->m_next == NULL) {
264 m = m_getm(m, size, M_WAIT, MT_DATA);
265 if (m == NULL)
266 return ENOBUFS;
268 m = m->m_next;
269 mleft = M_TRAILINGSPACE(m);
270 continue;
272 cplen = mleft > size ? size : mleft;
273 dst = mtod(m, char *) + m->m_len;
274 switch (type) {
275 case MB_MCUSTOM:
276 error = mbp->mb_copy(mbp, source, dst, cplen);
277 if (error)
278 return error;
279 break;
280 case MB_MINLINE:
281 for (src = source, count = cplen; count; count--)
282 *dst++ = *src++;
283 break;
284 case MB_MSYSTEM:
285 memcpy(dst, source, cplen);
286 break;
287 case MB_MUSER:
288 error = copyin(source, dst, cplen);
289 if (error)
290 return error;
291 break;
292 case MB_MZERO:
293 memset(dst, 0, cplen);
294 break;
296 size -= cplen;
297 source += cplen;
298 m->m_len += cplen;
299 mleft -= cplen;
300 mbp->mb_count += cplen;
302 mbp->mb_cur = m;
303 mbp->mb_mleft = mleft;
304 return 0;
308 mb_put_mbuf(struct mbchain *mbp, struct mbuf *m)
310 mbp->mb_cur->m_next = m;
311 while (m) {
312 mbp->mb_count += m->m_len;
313 if (m->m_next == NULL)
314 break;
315 m = m->m_next;
317 mbp->mb_mleft = M_TRAILINGSPACE(m);
318 mbp->mb_cur = m;
319 return 0;
323 * copies a uio scatter/gather list to an mbuf chain.
326 mb_put_uio(struct mbchain *mbp, struct uio *uiop, int size)
328 long left;
329 int mtype, error;
331 mtype = VMSPACE_IS_KERNEL_P(uiop->uio_vmspace) ? MB_MSYSTEM : MB_MUSER;
333 while (size > 0 && uiop->uio_resid) {
334 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
335 return EFBIG;
336 left = uiop->uio_iov->iov_len;
337 if (left == 0) {
338 uiop->uio_iov++;
339 uiop->uio_iovcnt--;
340 continue;
342 if (left > size)
343 left = size;
344 error = mb_put_mem(mbp, uiop->uio_iov->iov_base, left, mtype);
345 if (error)
346 return error;
347 uiop->uio_offset += left;
348 uiop->uio_resid -= left;
349 uiop->uio_iov->iov_base =
350 (char *)uiop->uio_iov->iov_base + left;
351 uiop->uio_iov->iov_len -= left;
352 size -= left;
354 return 0;
358 * Routines for fetching data from an mbuf chain
361 md_init(struct mdchain *mdp)
363 struct mbuf *m;
365 m = m_gethdr(M_WAIT, MT_DATA);
366 if (m == NULL)
367 return ENOBUFS;
368 m->m_len = 0;
369 md_initm(mdp, m);
370 return 0;
373 void
374 md_initm(struct mdchain *mdp, struct mbuf *m)
376 memset(mdp, 0, sizeof(*mdp));
377 mdp->md_top = mdp->md_cur = m;
378 mdp->md_pos = mtod(m, u_char*);
381 void
382 md_done(struct mdchain *mdp)
384 if (mdp->md_top) {
385 m_freem(mdp->md_top);
386 mdp->md_top = NULL;
391 * Append a separate mbuf chain. It is caller responsibility to prevent
392 * multiple calls to fetch/record routines.
394 void
395 md_append_record(struct mdchain *mdp, struct mbuf *top)
397 struct mbuf *m;
399 if (mdp->md_top == NULL) {
400 md_initm(mdp, top);
401 return;
403 m = mdp->md_top;
404 while (m->m_nextpkt)
405 m = m->m_nextpkt;
406 m->m_nextpkt = top;
407 top->m_nextpkt = NULL;
408 return;
412 * Put next record in place of existing
415 md_next_record(struct mdchain *mdp)
417 struct mbuf *m;
419 if (mdp->md_top == NULL)
420 return ENOENT;
421 m = mdp->md_top->m_nextpkt;
422 md_done(mdp);
423 if (m == NULL)
424 return ENOENT;
425 md_initm(mdp, m);
426 return 0;
430 md_get_uint8(struct mdchain *mdp, u_int8_t *x)
432 return md_get_mem(mdp, x, 1, MB_MINLINE);
436 md_get_uint16(struct mdchain *mdp, u_int16_t *x)
438 return md_get_mem(mdp, (void *)x, 2, MB_MINLINE);
442 md_get_uint16le(struct mdchain *mdp, u_int16_t *x)
444 u_int16_t v;
445 int error = md_get_uint16(mdp, &v);
447 *x = le16toh(v);
448 return error;
452 md_get_uint16be(struct mdchain *mdp, u_int16_t *x) {
453 u_int16_t v;
454 int error = md_get_uint16(mdp, &v);
456 *x = be16toh(v);
457 return error;
461 md_get_uint32(struct mdchain *mdp, u_int32_t *x)
463 return md_get_mem(mdp, (void *)x, 4, MB_MINLINE);
467 md_get_uint32be(struct mdchain *mdp, u_int32_t *x)
469 u_int32_t v;
470 int error;
472 error = md_get_uint32(mdp, &v);
473 *x = be32toh(v);
474 return error;
478 md_get_uint32le(struct mdchain *mdp, u_int32_t *x)
480 u_int32_t v;
481 int error;
483 error = md_get_uint32(mdp, &v);
484 *x = le32toh(v);
485 return error;
489 md_get_int64(struct mdchain *mdp, int64_t *x)
491 return md_get_mem(mdp, (void *)x, 8, MB_MINLINE);
495 md_get_int64be(struct mdchain *mdp, int64_t *x)
497 int64_t v;
498 int error;
500 error = md_get_int64(mdp, &v);
501 *x = be64toh(v);
502 return error;
506 md_get_int64le(struct mdchain *mdp, int64_t *x)
508 int64_t v;
509 int error;
511 error = md_get_int64(mdp, &v);
512 *x = le64toh(v);
513 return error;
517 md_get_mem(struct mdchain *mdp, void *targetv, int size, int type)
519 char *target = targetv;
520 struct mbuf *m = mdp->md_cur;
521 int error;
522 u_int count;
523 u_char *s;
525 while (size > 0) {
526 if (m == NULL) {
527 #ifdef MCHAIN_DEBUG
528 MBERROR(("incomplete copy\n"));
529 #endif
530 return EBADRPC;
532 s = mdp->md_pos;
533 count = mtod(m, u_char*) + m->m_len - s;
534 if (count == 0) {
535 mdp->md_cur = m = m->m_next;
536 if (m)
537 s = mdp->md_pos = mtod(m, void *);
538 continue;
540 if (count > size)
541 count = size;
542 size -= count;
543 mdp->md_pos += count;
544 if (target == NULL)
545 continue;
546 switch (type) {
547 case MB_MUSER:
548 error = copyout(s, target, count);
549 if (error)
550 return error;
551 break;
552 case MB_MSYSTEM:
553 memcpy(target, s, count);
554 break;
555 case MB_MINLINE:
556 while (count--)
557 *target++ = *s++;
558 continue;
560 target += count;
562 return 0;
566 md_get_mbuf(struct mdchain *mdp, int size, struct mbuf **ret)
568 struct mbuf *m = mdp->md_cur, *rm;
570 rm = m_copym(m, mdp->md_pos - mtod(m, u_char*), size, M_WAIT);
571 if (rm == NULL)
572 return EBADRPC;
573 md_get_mem(mdp, NULL, size, MB_MZERO);
574 *ret = rm;
575 return 0;
579 md_get_uio(struct mdchain *mdp, struct uio *uiop, int size)
581 char *uiocp;
582 long left;
583 int mtype, error;
585 mtype = VMSPACE_IS_KERNEL_P(uiop->uio_vmspace) ? MB_MSYSTEM : MB_MUSER;
586 while (size > 0 && uiop->uio_resid) {
587 if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
588 return EFBIG;
589 left = uiop->uio_iov->iov_len;
590 if (left == 0) {
591 uiop->uio_iov++;
592 uiop->uio_iovcnt--;
593 continue;
595 uiocp = uiop->uio_iov->iov_base;
596 if (left > size)
597 left = size;
598 error = md_get_mem(mdp, uiocp, left, mtype);
599 if (error)
600 return error;
601 uiop->uio_offset += left;
602 uiop->uio_resid -= left;
603 uiop->uio_iov->iov_base =
604 (char *)uiop->uio_iov->iov_base + left;
605 uiop->uio_iov->iov_len -= left;
606 size -= left;
608 return 0;