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 cplen
, error
, mleft
, count
;
208 mleft
= mbp
->mb_mleft
;
212 if (m
->m_next
== NULL
) {
213 m
->m_next
= m_getc(size
, MB_WAIT
, MT_DATA
);
218 mleft
= M_TRAILINGSPACE(m
);
221 cplen
= mleft
> size
? size
: mleft
;
222 dst
= mtod(m
, caddr_t
) + m
->m_len
;
225 error
= mbp
->mb_copy(mbp
, source
, dst
, cplen
);
230 for (src
= source
, count
= cplen
; count
; count
--)
234 bcopy(source
, dst
, cplen
);
237 error
= copyin(source
, dst
, cplen
);
249 mbp
->mb_count
+= cplen
;
252 mbp
->mb_mleft
= mleft
;
257 mb_put_mbuf(struct mbchain
*mbp
, struct mbuf
*m
)
259 mbp
->mb_cur
->m_next
= m
;
261 mbp
->mb_count
+= m
->m_len
;
262 if (m
->m_next
== NULL
)
266 mbp
->mb_mleft
= M_TRAILINGSPACE(m
);
272 * copies a uio scatter/gather list to an mbuf chain.
275 mb_put_uio(struct mbchain
*mbp
, struct uio
*uiop
, int size
)
280 mtype
= (uiop
->uio_segflg
== UIO_SYSSPACE
) ? MB_MSYSTEM
: MB_MUSER
;
282 while (size
> 0 && uiop
->uio_resid
) {
283 if (uiop
->uio_iovcnt
<= 0 || uiop
->uio_iov
== NULL
)
285 left
= uiop
->uio_iov
->iov_len
;
293 error
= mb_put_mem(mbp
, uiop
->uio_iov
->iov_base
, left
, mtype
);
296 uiop
->uio_offset
+= left
;
297 uiop
->uio_resid
-= left
;
298 uiop
->uio_iov
->iov_base
= (char *)uiop
->uio_iov
->iov_base
+ left
;
299 uiop
->uio_iov
->iov_len
-= left
;
306 * Routines for fetching data from an mbuf chain
309 md_init(struct mdchain
*mdp
)
313 m
= m_gethdr(MB_WAIT
, MT_DATA
);
316 m
->m_pkthdr
.rcvif
= NULL
;
323 md_initm(struct mdchain
*mdp
, struct mbuf
*m
)
325 bzero(mdp
, sizeof(*mdp
));
326 mdp
->md_top
= mdp
->md_cur
= m
;
327 mdp
->md_pos
= mtod(m
, u_char
*);
331 md_done(struct mdchain
*mdp
)
334 m_freem(mdp
->md_top
);
340 * Append a separate mbuf chain. It is caller responsibility to prevent
341 * multiple calls to fetch/record routines.
344 md_append_record(struct mdchain
*mdp
, struct mbuf
*top
)
348 if (mdp
->md_top
== NULL
) {
356 top
->m_nextpkt
= NULL
;
361 * Put next record in place of existing
364 md_next_record(struct mdchain
*mdp
)
368 if (mdp
->md_top
== NULL
)
370 m
= mdp
->md_top
->m_nextpkt
;
379 md_get_uint8(struct mdchain
*mdp
, u_int8_t
*x
)
381 return md_get_mem(mdp
, x
, 1, MB_MINLINE
);
385 md_get_uint16(struct mdchain
*mdp
, u_int16_t
*x
)
387 return md_get_mem(mdp
, (caddr_t
)x
, 2, MB_MINLINE
);
391 md_get_uint16le(struct mdchain
*mdp
, u_int16_t
*x
)
394 int error
= md_get_uint16(mdp
, &v
);
401 md_get_uint16be(struct mdchain
*mdp
, u_int16_t
*x
) {
403 int error
= md_get_uint16(mdp
, &v
);
410 md_get_uint32(struct mdchain
*mdp
, u_int32_t
*x
)
412 return md_get_mem(mdp
, (caddr_t
)x
, 4, MB_MINLINE
);
416 md_get_uint32be(struct mdchain
*mdp
, u_int32_t
*x
)
421 error
= md_get_uint32(mdp
, &v
);
427 md_get_uint32le(struct mdchain
*mdp
, u_int32_t
*x
)
432 error
= md_get_uint32(mdp
, &v
);
438 md_get_int64(struct mdchain
*mdp
, int64_t *x
)
440 return md_get_mem(mdp
, (caddr_t
)x
, 8, MB_MINLINE
);
444 md_get_int64be(struct mdchain
*mdp
, int64_t *x
)
449 error
= md_get_int64(mdp
, &v
);
455 md_get_int64le(struct mdchain
*mdp
, int64_t *x
)
460 error
= md_get_int64(mdp
, &v
);
466 md_get_mem(struct mdchain
*mdp
, caddr_t target
, int size
, int type
)
468 struct mbuf
*m
= mdp
->md_cur
;
475 MBERROR("incomplete copy\n");
479 count
= mtod(m
, u_char
*) + m
->m_len
- s
;
481 mdp
->md_cur
= m
= m
->m_next
;
483 s
= mdp
->md_pos
= mtod(m
, caddr_t
);
489 mdp
->md_pos
+= count
;
494 error
= copyout(s
, target
, count
);
499 bcopy(s
, target
, count
);
512 md_get_mbuf(struct mdchain
*mdp
, int size
, struct mbuf
**ret
)
514 struct mbuf
*m
= mdp
->md_cur
, *rm
;
516 rm
= m_copym(m
, mdp
->md_pos
- mtod(m
, u_char
*), size
, MB_WAIT
);
519 md_get_mem(mdp
, NULL
, size
, MB_MZERO
);
525 md_get_uio(struct mdchain
*mdp
, struct uio
*uiop
, int size
)
531 mtype
= (uiop
->uio_segflg
== UIO_SYSSPACE
) ? MB_MSYSTEM
: MB_MUSER
;
532 while (size
> 0 && uiop
->uio_resid
) {
533 if (uiop
->uio_iovcnt
<= 0 || uiop
->uio_iov
== NULL
)
535 left
= uiop
->uio_iov
->iov_len
;
541 uiocp
= uiop
->uio_iov
->iov_base
;
544 error
= md_get_mem(mdp
, uiocp
, left
, mtype
);
547 uiop
->uio_offset
+= left
;
548 uiop
->uio_resid
-= left
;
549 uiop
->uio_iov
->iov_base
= (char *)uiop
->uio_iov
->iov_base
+ left
;
550 uiop
->uio_iov
->iov_len
-= left
;