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 * 4. Neither the name of the author nor the names of any co-contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29 * $FreeBSD: src/sys/kern/subr_mchain.c,v 1.2.2.2 2002/04/13 12:46:40 bp Exp $
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/kernel.h>
36 #include <sys/endian.h>
37 #include <sys/errno.h>
39 #include <sys/module.h>
42 #include <sys/mchain.h>
44 MODULE_VERSION(libmchain
, 1);
46 #define MBERROR(format, ...) kprintf("%s(%d): "format, __func__ , \
47 __LINE__ , ## __VA_ARGS__)
49 #define MBPANIC(format, ...) kprintf("%s(%d): "format, __func__ , \
50 __LINE__ , ## __VA_ARGS__)
53 * Various helper functions
56 m_fixhdr(struct mbuf
*m0
)
65 m0
->m_pkthdr
.len
= len
;
70 mb_init(struct mbchain
*mbp
)
74 m
= m_gethdr(M_WAITOK
, MT_DATA
);
77 m
->m_pkthdr
.rcvif
= NULL
;
84 mb_initm(struct mbchain
*mbp
, struct mbuf
*m
)
86 bzero(mbp
, sizeof(*mbp
));
87 mbp
->mb_top
= mbp
->mb_cur
= m
;
88 mbp
->mb_mleft
= M_TRAILINGSPACE(m
);
92 mb_done(struct mbchain
*mbp
)
101 mb_detach(struct mbchain
*mbp
)
111 mb_fixhdr(struct mbchain
*mbp
)
113 return mbp
->mb_top
->m_pkthdr
.len
= m_fixhdr(mbp
->mb_top
);
117 * Check if object of size 'size' fit to the current position and
118 * allocate new mbuf if not. Advance pointers and increase length of mbuf(s).
119 * Return pointer to the object placeholder or NULL if any error occured.
120 * Note: size should be <= MLEN
123 mb_reserve(struct mbchain
*mbp
, int size
)
129 panic("mb_reserve: size = %d", size
);
131 if (mbp
->mb_mleft
< size
) {
132 mn
= m_get(M_WAITOK
, MT_DATA
);
135 mbp
->mb_cur
= m
->m_next
= mn
;
138 mbp
->mb_mleft
= M_TRAILINGSPACE(m
);
140 mbp
->mb_mleft
-= size
;
141 mbp
->mb_count
+= size
;
142 bpos
= mtod(m
, caddr_t
) + m
->m_len
;
148 mb_put_uint8(struct mbchain
*mbp
, u_int8_t x
)
150 return mb_put_mem(mbp
, (caddr_t
)&x
, sizeof(x
), MB_MSYSTEM
);
154 mb_put_uint16be(struct mbchain
*mbp
, u_int16_t x
)
157 return mb_put_mem(mbp
, (caddr_t
)&x
, sizeof(x
), MB_MSYSTEM
);
161 mb_put_uint16le(struct mbchain
*mbp
, u_int16_t x
)
164 return mb_put_mem(mbp
, (caddr_t
)&x
, sizeof(x
), MB_MSYSTEM
);
168 mb_put_uint32be(struct mbchain
*mbp
, u_int32_t x
)
171 return mb_put_mem(mbp
, (caddr_t
)&x
, sizeof(x
), MB_MSYSTEM
);
175 mb_put_uint32le(struct mbchain
*mbp
, u_int32_t x
)
178 return mb_put_mem(mbp
, (caddr_t
)&x
, sizeof(x
), MB_MSYSTEM
);
182 mb_put_int64be(struct mbchain
*mbp
, int64_t x
)
185 return mb_put_mem(mbp
, (caddr_t
)&x
, sizeof(x
), MB_MSYSTEM
);
189 mb_put_int64le(struct mbchain
*mbp
, int64_t x
)
192 return mb_put_mem(mbp
, (caddr_t
)&x
, sizeof(x
), MB_MSYSTEM
);
196 mb_put_mem(struct mbchain
*mbp
, c_caddr_t source
, int size
, int type
)
201 int error
, mleft
, count
;
202 size_t cplen
, srclen
, dstlen
;
205 mleft
= mbp
->mb_mleft
;
209 if (m
->m_next
== NULL
) {
210 m
->m_next
= m_getc(size
, M_WAITOK
, MT_DATA
);
211 if (m
->m_next
== NULL
)
215 mleft
= M_TRAILINGSPACE(m
);
218 cplen
= mleft
> size
? size
: mleft
;
219 srclen
= dstlen
= cplen
;
220 dst
= mtod(m
, caddr_t
) + m
->m_len
;
225 error
= mbp
->mb_copy(mbp
, source
, dst
, &srclen
, &dstlen
);
230 for (src
= source
, count
= cplen
; count
; count
--)
234 bcopy(source
, dst
, cplen
);
237 error
= copyin(source
, dst
, cplen
);
249 mbp
->mb_count
+= dstlen
;
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
=
299 (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(M_WAITOK
, 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
);
403 md_get_uint16be(struct mdchain
*mdp
, u_int16_t
*x
) {
405 int error
= md_get_uint16(mdp
, &v
);
413 md_get_uint32(struct mdchain
*mdp
, u_int32_t
*x
)
415 return md_get_mem(mdp
, (caddr_t
)x
, 4, MB_MINLINE
);
419 md_get_uint32be(struct mdchain
*mdp
, u_int32_t
*x
)
424 error
= md_get_uint32(mdp
, &v
);
431 md_get_uint32le(struct mdchain
*mdp
, u_int32_t
*x
)
436 error
= md_get_uint32(mdp
, &v
);
443 md_get_int64(struct mdchain
*mdp
, int64_t *x
)
445 return md_get_mem(mdp
, (caddr_t
)x
, 8, MB_MINLINE
);
449 md_get_int64be(struct mdchain
*mdp
, int64_t *x
)
454 error
= md_get_int64(mdp
, &v
);
461 md_get_int64le(struct mdchain
*mdp
, int64_t *x
)
466 error
= md_get_int64(mdp
, &v
);
473 md_get_mem(struct mdchain
*mdp
, caddr_t target
, int size
, int type
)
475 struct mbuf
*m
= mdp
->md_cur
;
482 MBERROR("incomplete copy\n");
486 count
= mtod(m
, u_char
*) + m
->m_len
- s
;
488 mdp
->md_cur
= m
= m
->m_next
;
490 s
= mdp
->md_pos
= mtod(m
, caddr_t
);
496 mdp
->md_pos
+= count
;
501 error
= copyout(s
, target
, count
);
506 bcopy(s
, target
, count
);
519 md_get_mbuf(struct mdchain
*mdp
, int size
, struct mbuf
**ret
)
521 struct mbuf
*m
= mdp
->md_cur
, *rm
;
523 rm
= m_copym(m
, mdp
->md_pos
- mtod(m
, u_char
*), size
, M_WAITOK
);
526 md_get_mem(mdp
, NULL
, size
, MB_MZERO
);
532 md_get_uio(struct mdchain
*mdp
, struct uio
*uiop
, int size
)
538 mtype
= (uiop
->uio_segflg
== UIO_SYSSPACE
) ? MB_MSYSTEM
: MB_MUSER
;
539 while (size
> 0 && uiop
->uio_resid
) {
540 if (uiop
->uio_iovcnt
<= 0 || uiop
->uio_iov
== NULL
)
542 left
= uiop
->uio_iov
->iov_len
;
548 uiocp
= uiop
->uio_iov
->iov_base
;
551 error
= md_get_mem(mdp
, uiocp
, left
, mtype
);
554 uiop
->uio_offset
+= left
;
555 uiop
->uio_resid
-= left
;
556 uiop
->uio_iov
->iov_base
=
557 (char *)uiop
->uio_iov
->iov_base
+ left
;
558 uiop
->uio_iov
->iov_len
-= left
;