2 * Copyright (c) 2000, 2001 Boris Popov
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
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.
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
32 * $FreeBSD: src/sys/kern/subr_mchain.c,v 1.2.2.2 2002/04/13 12:46:40 bp Exp $
33 * $DragonFly: src/sys/kern/libmchain/subr_mchain.c,v 1.6 2007/10/20 09:38:01 sephe Exp $
37 #include <sys/param.h>
38 #include <sys/systm.h>
39 #include <sys/kernel.h>
40 #include <sys/errno.h>
41 #include <sys/malloc.h>
43 #include <sys/module.h>
46 #include <sys/mchain.h>
48 MODULE_VERSION(libmchain
, 1);
50 #define MBERROR(format, args...) kprintf("%s(%d): "format, __func__ , \
53 #define MBPANIC(format, args...) kprintf("%s(%d): "format, __func__ , \
57 * Various helper functions
60 m_fixhdr(struct mbuf
*m0
)
69 m0
->m_pkthdr
.len
= len
;
74 mb_init(struct mbchain
*mbp
)
78 m
= m_gethdr(MB_WAIT
, MT_DATA
);
81 m
->m_pkthdr
.rcvif
= NULL
;
88 mb_initm(struct mbchain
*mbp
, struct mbuf
*m
)
90 bzero(mbp
, sizeof(*mbp
));
91 mbp
->mb_top
= mbp
->mb_cur
= m
;
92 mbp
->mb_mleft
= M_TRAILINGSPACE(m
);
96 mb_done(struct mbchain
*mbp
)
105 mb_detach(struct mbchain
*mbp
)
115 mb_fixhdr(struct mbchain
*mbp
)
117 return mbp
->mb_top
->m_pkthdr
.len
= m_fixhdr(mbp
->mb_top
);
121 * Check if object of size 'size' fit to the current position and
122 * allocate new mbuf if not. Advance pointers and increase length of mbuf(s).
123 * Return pointer to the object placeholder or NULL if any error occured.
124 * Note: size should be <= MLEN
127 mb_reserve(struct mbchain
*mbp
, int size
)
133 panic("mb_reserve: size = %d\n", size
);
135 if (mbp
->mb_mleft
< size
) {
136 mn
= m_get(MB_WAIT
, MT_DATA
);
139 mbp
->mb_cur
= m
->m_next
= mn
;
142 mbp
->mb_mleft
= M_TRAILINGSPACE(m
);
144 mbp
->mb_mleft
-= size
;
145 mbp
->mb_count
+= size
;
146 bpos
= mtod(m
, caddr_t
) + m
->m_len
;
152 mb_put_uint8(struct mbchain
*mbp
, u_int8_t x
)
154 return mb_put_mem(mbp
, (caddr_t
)&x
, sizeof(x
), MB_MSYSTEM
);
158 mb_put_uint16be(struct mbchain
*mbp
, u_int16_t x
)
161 return mb_put_mem(mbp
, (caddr_t
)&x
, sizeof(x
), MB_MSYSTEM
);
165 mb_put_uint16le(struct mbchain
*mbp
, u_int16_t x
)
168 return mb_put_mem(mbp
, (caddr_t
)&x
, sizeof(x
), MB_MSYSTEM
);
172 mb_put_uint32be(struct mbchain
*mbp
, u_int32_t x
)
175 return mb_put_mem(mbp
, (caddr_t
)&x
, sizeof(x
), MB_MSYSTEM
);
179 mb_put_uint32le(struct mbchain
*mbp
, u_int32_t x
)
182 return mb_put_mem(mbp
, (caddr_t
)&x
, sizeof(x
), MB_MSYSTEM
);
186 mb_put_int64be(struct mbchain
*mbp
, int64_t x
)
189 return mb_put_mem(mbp
, (caddr_t
)&x
, sizeof(x
), MB_MSYSTEM
);
193 mb_put_int64le(struct mbchain
*mbp
, int64_t x
)
196 return mb_put_mem(mbp
, (caddr_t
)&x
, sizeof(x
), MB_MSYSTEM
);
200 mb_put_mem(struct mbchain
*mbp
, c_caddr_t source
, int size
, int type
)
205 int error
, mleft
, count
;
209 mleft
= mbp
->mb_mleft
;
213 if (m
->m_next
== NULL
) {
214 m
->m_next
= m_getc(size
, MB_WAIT
, MT_DATA
);
219 mleft
= M_TRAILINGSPACE(m
);
222 cplen
= mleft
> size
? size
: mleft
;
223 dst
= mtod(m
, caddr_t
) + m
->m_len
;
226 error
= mbp
->mb_copy(mbp
, source
, dst
, cplen
);
231 for (src
= source
, count
= cplen
; count
; count
--)
235 bcopy(source
, dst
, cplen
);
238 error
= copyin(source
, dst
, cplen
);
250 mbp
->mb_count
+= cplen
;
253 mbp
->mb_mleft
= mleft
;
258 mb_put_mbuf(struct mbchain
*mbp
, struct mbuf
*m
)
260 mbp
->mb_cur
->m_next
= m
;
262 mbp
->mb_count
+= m
->m_len
;
263 if (m
->m_next
== NULL
)
267 mbp
->mb_mleft
= M_TRAILINGSPACE(m
);
273 * copies a uio scatter/gather list to an mbuf chain.
276 mb_put_uio(struct mbchain
*mbp
, struct uio
*uiop
, int size
)
281 mtype
= (uiop
->uio_segflg
== UIO_SYSSPACE
) ? MB_MSYSTEM
: MB_MUSER
;
283 while (size
> 0 && uiop
->uio_resid
) {
284 if (uiop
->uio_iovcnt
<= 0 || uiop
->uio_iov
== NULL
)
286 left
= uiop
->uio_iov
->iov_len
;
294 error
= mb_put_mem(mbp
, uiop
->uio_iov
->iov_base
, left
, mtype
);
297 uiop
->uio_offset
+= left
;
298 uiop
->uio_resid
-= left
;
299 uiop
->uio_iov
->iov_base
= (char *)uiop
->uio_iov
->iov_base
+ left
;
300 uiop
->uio_iov
->iov_len
-= left
;
307 * Routines for fetching data from an mbuf chain
310 md_init(struct mdchain
*mdp
)
314 m
= m_gethdr(MB_WAIT
, MT_DATA
);
317 m
->m_pkthdr
.rcvif
= NULL
;
324 md_initm(struct mdchain
*mdp
, struct mbuf
*m
)
326 bzero(mdp
, sizeof(*mdp
));
327 mdp
->md_top
= mdp
->md_cur
= m
;
328 mdp
->md_pos
= mtod(m
, u_char
*);
332 md_done(struct mdchain
*mdp
)
335 m_freem(mdp
->md_top
);
341 * Append a separate mbuf chain. It is caller responsibility to prevent
342 * multiple calls to fetch/record routines.
345 md_append_record(struct mdchain
*mdp
, struct mbuf
*top
)
349 if (mdp
->md_top
== NULL
) {
357 top
->m_nextpkt
= NULL
;
362 * Put next record in place of existing
365 md_next_record(struct mdchain
*mdp
)
369 if (mdp
->md_top
== NULL
)
371 m
= mdp
->md_top
->m_nextpkt
;
380 md_get_uint8(struct mdchain
*mdp
, u_int8_t
*x
)
382 return md_get_mem(mdp
, x
, 1, MB_MINLINE
);
386 md_get_uint16(struct mdchain
*mdp
, u_int16_t
*x
)
388 return md_get_mem(mdp
, (caddr_t
)x
, 2, MB_MINLINE
);
392 md_get_uint16le(struct mdchain
*mdp
, u_int16_t
*x
)
395 int error
= md_get_uint16(mdp
, &v
);
402 md_get_uint16be(struct mdchain
*mdp
, u_int16_t
*x
) {
404 int error
= md_get_uint16(mdp
, &v
);
411 md_get_uint32(struct mdchain
*mdp
, u_int32_t
*x
)
413 return md_get_mem(mdp
, (caddr_t
)x
, 4, MB_MINLINE
);
417 md_get_uint32be(struct mdchain
*mdp
, u_int32_t
*x
)
422 error
= md_get_uint32(mdp
, &v
);
428 md_get_uint32le(struct mdchain
*mdp
, u_int32_t
*x
)
433 error
= md_get_uint32(mdp
, &v
);
439 md_get_int64(struct mdchain
*mdp
, int64_t *x
)
441 return md_get_mem(mdp
, (caddr_t
)x
, 8, MB_MINLINE
);
445 md_get_int64be(struct mdchain
*mdp
, int64_t *x
)
450 error
= md_get_int64(mdp
, &v
);
456 md_get_int64le(struct mdchain
*mdp
, int64_t *x
)
461 error
= md_get_int64(mdp
, &v
);
467 md_get_mem(struct mdchain
*mdp
, caddr_t target
, int size
, int type
)
469 struct mbuf
*m
= mdp
->md_cur
;
476 MBERROR("incomplete copy\n");
480 count
= mtod(m
, u_char
*) + m
->m_len
- s
;
482 mdp
->md_cur
= m
= m
->m_next
;
484 s
= mdp
->md_pos
= mtod(m
, caddr_t
);
490 mdp
->md_pos
+= count
;
495 error
= copyout(s
, target
, count
);
500 bcopy(s
, target
, count
);
513 md_get_mbuf(struct mdchain
*mdp
, int size
, struct mbuf
**ret
)
515 struct mbuf
*m
= mdp
->md_cur
, *rm
;
517 rm
= m_copym(m
, mdp
->md_pos
- mtod(m
, u_char
*), size
, MB_WAIT
);
520 md_get_mem(mdp
, NULL
, size
, MB_MZERO
);
526 md_get_uio(struct mdchain
*mdp
, struct uio
*uiop
, int size
)
532 mtype
= (uiop
->uio_segflg
== UIO_SYSSPACE
) ? MB_MSYSTEM
: MB_MUSER
;
533 while (size
> 0 && uiop
->uio_resid
) {
534 if (uiop
->uio_iovcnt
<= 0 || uiop
->uio_iov
== NULL
)
536 left
= uiop
->uio_iov
->iov_len
;
542 uiocp
= uiop
->uio_iov
->iov_base
;
545 error
= md_get_mem(mdp
, uiocp
, left
, mtype
);
548 uiop
->uio_offset
+= left
;
549 uiop
->uio_resid
-= left
;
550 uiop
->uio_iov
->iov_base
= (char *)uiop
->uio_iov
->iov_base
+ left
;
551 uiop
->uio_iov
->iov_len
-= left
;