1 /* $NetBSD: subr_mchain.c,v 1.17 2009/03/18 17:06:53 cegger Exp $ */
4 * Copyright (c) 2000, 2001 Boris Popov
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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>
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
55 m_getm(struct mbuf
*m
, int len
, int how
, int type
)
57 struct mbuf
*top
, *tail
, *mp
, *mtail
= NULL
;
61 mp
= m_get(how
, type
);
64 else if (len
> MINCLSIZE
) {
66 if ((mp
->m_flags
& M_EXT
) == 0) {
72 len
-= M_TRAILINGSPACE(mp
);
75 for (mtail
= m
; mtail
->m_next
!= NULL
; mtail
= mtail
->m_next
);
81 mp
= m_get(how
, type
);
87 if (len
> MINCLSIZE
) {
89 if ((mp
->m_flags
& M_EXT
) == 0)
94 len
-= M_TRAILINGSPACE(mp
);
106 #endif /* __NetBSD__ */
109 * Various helper functions
112 m_fixhdr(struct mbuf
*m0
)
121 m0
->m_pkthdr
.len
= len
;
126 mb_init(struct mbchain
*mbp
)
130 m
= m_gethdr(M_WAIT
, MT_DATA
);
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
);
147 mb_done(struct mbchain
*mbp
)
150 m_freem(mbp
->mb_top
);
156 mb_detach(struct mbchain
*mbp
)
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
178 mb_reserve(struct mbchain
*mbp
, int size
)
184 panic("mb_reserve: size = %d", size
);
186 if (mbp
->mb_mleft
< size
) {
187 mn
= m_get(M_WAIT
, MT_DATA
);
190 mbp
->mb_cur
= m
->m_next
= mn
;
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
;
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
)
212 return mb_put_mem(mbp
, (void *)&x
, sizeof(x
), MB_MSYSTEM
);
216 mb_put_uint16le(struct mbchain
*mbp
, u_int16_t x
)
219 return mb_put_mem(mbp
, (void *)&x
, sizeof(x
), MB_MSYSTEM
);
223 mb_put_uint32be(struct mbchain
*mbp
, u_int32_t x
)
226 return mb_put_mem(mbp
, (void *)&x
, sizeof(x
), MB_MSYSTEM
);
230 mb_put_uint32le(struct mbchain
*mbp
, u_int32_t x
)
233 return mb_put_mem(mbp
, (void *)&x
, sizeof(x
), MB_MSYSTEM
);
237 mb_put_int64be(struct mbchain
*mbp
, int64_t x
)
240 return mb_put_mem(mbp
, (void *)&x
, sizeof(x
), MB_MSYSTEM
);
244 mb_put_int64le(struct mbchain
*mbp
, int64_t 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
)
256 int cplen
, error
, mleft
, count
;
259 mleft
= mbp
->mb_mleft
;
263 if (m
->m_next
== NULL
) {
264 m
= m_getm(m
, size
, M_WAIT
, MT_DATA
);
269 mleft
= M_TRAILINGSPACE(m
);
272 cplen
= mleft
> size
? size
: mleft
;
273 dst
= mtod(m
, char *) + m
->m_len
;
276 error
= mbp
->mb_copy(mbp
, source
, dst
, cplen
);
281 for (src
= source
, count
= cplen
; count
; count
--)
285 memcpy(dst
, source
, cplen
);
288 error
= copyin(source
, dst
, cplen
);
293 memset(dst
, 0, cplen
);
300 mbp
->mb_count
+= cplen
;
303 mbp
->mb_mleft
= mleft
;
308 mb_put_mbuf(struct mbchain
*mbp
, struct mbuf
*m
)
310 mbp
->mb_cur
->m_next
= m
;
312 mbp
->mb_count
+= m
->m_len
;
313 if (m
->m_next
== NULL
)
317 mbp
->mb_mleft
= M_TRAILINGSPACE(m
);
323 * copies a uio scatter/gather list to an mbuf chain.
326 mb_put_uio(struct mbchain
*mbp
, struct uio
*uiop
, int size
)
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
)
336 left
= uiop
->uio_iov
->iov_len
;
344 error
= mb_put_mem(mbp
, uiop
->uio_iov
->iov_base
, left
, mtype
);
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
;
358 * Routines for fetching data from an mbuf chain
361 md_init(struct mdchain
*mdp
)
365 m
= m_gethdr(M_WAIT
, MT_DATA
);
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
*);
382 md_done(struct mdchain
*mdp
)
385 m_freem(mdp
->md_top
);
391 * Append a separate mbuf chain. It is caller responsibility to prevent
392 * multiple calls to fetch/record routines.
395 md_append_record(struct mdchain
*mdp
, struct mbuf
*top
)
399 if (mdp
->md_top
== NULL
) {
407 top
->m_nextpkt
= NULL
;
412 * Put next record in place of existing
415 md_next_record(struct mdchain
*mdp
)
419 if (mdp
->md_top
== NULL
)
421 m
= mdp
->md_top
->m_nextpkt
;
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
)
445 int error
= md_get_uint16(mdp
, &v
);
452 md_get_uint16be(struct mdchain
*mdp
, u_int16_t
*x
) {
454 int error
= md_get_uint16(mdp
, &v
);
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
)
472 error
= md_get_uint32(mdp
, &v
);
478 md_get_uint32le(struct mdchain
*mdp
, u_int32_t
*x
)
483 error
= md_get_uint32(mdp
, &v
);
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
)
500 error
= md_get_int64(mdp
, &v
);
506 md_get_int64le(struct mdchain
*mdp
, int64_t *x
)
511 error
= md_get_int64(mdp
, &v
);
517 md_get_mem(struct mdchain
*mdp
, void *targetv
, int size
, int type
)
519 char *target
= targetv
;
520 struct mbuf
*m
= mdp
->md_cur
;
528 MBERROR(("incomplete copy\n"));
533 count
= mtod(m
, u_char
*) + m
->m_len
- s
;
535 mdp
->md_cur
= m
= m
->m_next
;
537 s
= mdp
->md_pos
= mtod(m
, void *);
543 mdp
->md_pos
+= count
;
548 error
= copyout(s
, target
, count
);
553 memcpy(target
, s
, count
);
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
);
573 md_get_mem(mdp
, NULL
, size
, MB_MZERO
);
579 md_get_uio(struct mdchain
*mdp
, struct uio
*uiop
, int size
)
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
)
589 left
= uiop
->uio_iov
->iov_len
;
595 uiocp
= uiop
->uio_iov
->iov_base
;
598 error
= md_get_mem(mdp
, uiocp
, left
, mtype
);
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
;