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
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
33 #include <sys/param.h>
34 #include <sys/systm.h>
35 #include <sys/endian.h>
36 #include <sys/errno.h>
38 #include <sys/module.h>
41 #include <sys/mchain.h>
43 MODULE_VERSION(libmchain
, 1);
45 #define MBERROR(format, ...) printf("%s(%d): "format, __func__ , \
46 __LINE__ , ## __VA_ARGS__)
48 #define MBPANIC(format, ...) printf("%s(%d): "format, __func__ , \
49 __LINE__ , ## __VA_ARGS__)
52 * Various helper functions
55 mb_init(struct mbchain
*mbp
)
59 m
= m_gethdr(M_WAIT
, MT_DATA
);
66 mb_initm(struct mbchain
*mbp
, struct mbuf
*m
)
68 bzero(mbp
, sizeof(*mbp
));
69 mbp
->mb_top
= mbp
->mb_cur
= m
;
70 mbp
->mb_mleft
= M_TRAILINGSPACE(m
);
74 mb_done(struct mbchain
*mbp
)
83 mb_detach(struct mbchain
*mbp
)
93 mb_fixhdr(struct mbchain
*mbp
)
95 return mbp
->mb_top
->m_pkthdr
.len
= m_fixhdr(mbp
->mb_top
);
99 * Check if object of size 'size' fit to the current position and
100 * allocate new mbuf if not. Advance pointers and increase length of mbuf(s).
101 * Return pointer to the object placeholder or NULL if any error occured.
102 * Note: size should be <= MLEN
105 mb_reserve(struct mbchain
*mbp
, int size
)
111 panic("mb_reserve: size = %d\n", size
);
113 if (mbp
->mb_mleft
< size
) {
114 mn
= m_get(M_WAIT
, MT_DATA
);
115 mbp
->mb_cur
= m
->m_next
= mn
;
118 mbp
->mb_mleft
= M_TRAILINGSPACE(m
);
120 mbp
->mb_mleft
-= size
;
121 mbp
->mb_count
+= size
;
122 bpos
= mtod(m
, caddr_t
) + m
->m_len
;
128 mb_put_uint8(struct mbchain
*mbp
, u_int8_t x
)
130 return mb_put_mem(mbp
, (caddr_t
)&x
, sizeof(x
), MB_MSYSTEM
);
134 mb_put_uint16be(struct mbchain
*mbp
, u_int16_t x
)
137 return mb_put_mem(mbp
, (caddr_t
)&x
, sizeof(x
), MB_MSYSTEM
);
141 mb_put_uint16le(struct mbchain
*mbp
, u_int16_t x
)
144 return mb_put_mem(mbp
, (caddr_t
)&x
, sizeof(x
), MB_MSYSTEM
);
148 mb_put_uint32be(struct mbchain
*mbp
, u_int32_t x
)
151 return mb_put_mem(mbp
, (caddr_t
)&x
, sizeof(x
), MB_MSYSTEM
);
155 mb_put_uint32le(struct mbchain
*mbp
, u_int32_t x
)
158 return mb_put_mem(mbp
, (caddr_t
)&x
, sizeof(x
), MB_MSYSTEM
);
162 mb_put_int64be(struct mbchain
*mbp
, int64_t x
)
165 return mb_put_mem(mbp
, (caddr_t
)&x
, sizeof(x
), MB_MSYSTEM
);
169 mb_put_int64le(struct mbchain
*mbp
, int64_t x
)
172 return mb_put_mem(mbp
, (caddr_t
)&x
, sizeof(x
), MB_MSYSTEM
);
176 mb_put_mem(struct mbchain
*mbp
, c_caddr_t source
, int size
, int type
)
181 int cplen
, error
, mleft
, count
;
182 size_t srclen
, dstlen
;
185 mleft
= mbp
->mb_mleft
;
189 if (m
->m_next
== NULL
)
190 m
= m_getm(m
, size
, M_WAIT
, MT_DATA
);
193 mleft
= M_TRAILINGSPACE(m
);
196 cplen
= mleft
> size
? size
: mleft
;
197 srclen
= dstlen
= cplen
;
198 dst
= mtod(m
, caddr_t
) + m
->m_len
;
203 error
= mbp
->mb_copy(mbp
, source
, dst
, &srclen
, &dstlen
);
208 for (src
= source
, count
= cplen
; count
; count
--)
212 bcopy(source
, dst
, cplen
);
215 error
= copyin(source
, dst
, cplen
);
227 mbp
->mb_count
+= dstlen
;
230 mbp
->mb_mleft
= mleft
;
235 mb_put_mbuf(struct mbchain
*mbp
, struct mbuf
*m
)
237 mbp
->mb_cur
->m_next
= m
;
239 mbp
->mb_count
+= m
->m_len
;
240 if (m
->m_next
== NULL
)
244 mbp
->mb_mleft
= M_TRAILINGSPACE(m
);
250 * copies a uio scatter/gather list to an mbuf chain.
253 mb_put_uio(struct mbchain
*mbp
, struct uio
*uiop
, int size
)
258 mtype
= (uiop
->uio_segflg
== UIO_SYSSPACE
) ? MB_MSYSTEM
: MB_MUSER
;
260 while (size
> 0 && uiop
->uio_resid
) {
261 if (uiop
->uio_iovcnt
<= 0 || uiop
->uio_iov
== NULL
)
263 left
= uiop
->uio_iov
->iov_len
;
271 error
= mb_put_mem(mbp
, uiop
->uio_iov
->iov_base
, left
, mtype
);
274 uiop
->uio_offset
+= left
;
275 uiop
->uio_resid
-= left
;
276 uiop
->uio_iov
->iov_base
=
277 (char *)uiop
->uio_iov
->iov_base
+ left
;
278 uiop
->uio_iov
->iov_len
-= left
;
285 * Routines for fetching data from an mbuf chain
288 md_init(struct mdchain
*mdp
)
292 m
= m_gethdr(M_WAIT
, MT_DATA
);
299 md_initm(struct mdchain
*mdp
, struct mbuf
*m
)
301 bzero(mdp
, sizeof(*mdp
));
302 mdp
->md_top
= mdp
->md_cur
= m
;
303 mdp
->md_pos
= mtod(m
, u_char
*);
307 md_done(struct mdchain
*mdp
)
310 m_freem(mdp
->md_top
);
316 * Append a separate mbuf chain. It is caller responsibility to prevent
317 * multiple calls to fetch/record routines.
320 md_append_record(struct mdchain
*mdp
, struct mbuf
*top
)
324 if (mdp
->md_top
== NULL
) {
332 top
->m_nextpkt
= NULL
;
337 * Put next record in place of existing
340 md_next_record(struct mdchain
*mdp
)
344 if (mdp
->md_top
== NULL
)
346 m
= mdp
->md_top
->m_nextpkt
;
355 md_get_uint8(struct mdchain
*mdp
, u_int8_t
*x
)
357 return md_get_mem(mdp
, x
, 1, MB_MINLINE
);
361 md_get_uint16(struct mdchain
*mdp
, u_int16_t
*x
)
363 return md_get_mem(mdp
, (caddr_t
)x
, 2, MB_MINLINE
);
367 md_get_uint16le(struct mdchain
*mdp
, u_int16_t
*x
)
370 int error
= md_get_uint16(mdp
, &v
);
378 md_get_uint16be(struct mdchain
*mdp
, u_int16_t
*x
) {
380 int error
= md_get_uint16(mdp
, &v
);
388 md_get_uint32(struct mdchain
*mdp
, u_int32_t
*x
)
390 return md_get_mem(mdp
, (caddr_t
)x
, 4, MB_MINLINE
);
394 md_get_uint32be(struct mdchain
*mdp
, u_int32_t
*x
)
399 error
= md_get_uint32(mdp
, &v
);
406 md_get_uint32le(struct mdchain
*mdp
, u_int32_t
*x
)
411 error
= md_get_uint32(mdp
, &v
);
418 md_get_int64(struct mdchain
*mdp
, int64_t *x
)
420 return md_get_mem(mdp
, (caddr_t
)x
, 8, MB_MINLINE
);
424 md_get_int64be(struct mdchain
*mdp
, int64_t *x
)
429 error
= md_get_int64(mdp
, &v
);
436 md_get_int64le(struct mdchain
*mdp
, int64_t *x
)
441 error
= md_get_int64(mdp
, &v
);
448 md_get_mem(struct mdchain
*mdp
, caddr_t target
, int size
, int type
)
450 struct mbuf
*m
= mdp
->md_cur
;
457 MBERROR("incomplete copy\n");
461 count
= mtod(m
, u_char
*) + m
->m_len
- s
;
463 mdp
->md_cur
= m
= m
->m_next
;
465 s
= mdp
->md_pos
= mtod(m
, caddr_t
);
471 mdp
->md_pos
+= count
;
476 error
= copyout(s
, target
, count
);
481 bcopy(s
, target
, count
);
494 md_get_mbuf(struct mdchain
*mdp
, int size
, struct mbuf
**ret
)
496 struct mbuf
*m
= mdp
->md_cur
, *rm
;
498 rm
= m_copym(m
, mdp
->md_pos
- mtod(m
, u_char
*), size
, M_WAIT
);
499 md_get_mem(mdp
, NULL
, size
, MB_MZERO
);
505 md_get_uio(struct mdchain
*mdp
, struct uio
*uiop
, int size
)
511 mtype
= (uiop
->uio_segflg
== UIO_SYSSPACE
) ? MB_MSYSTEM
: MB_MUSER
;
512 while (size
> 0 && uiop
->uio_resid
) {
513 if (uiop
->uio_iovcnt
<= 0 || uiop
->uio_iov
== NULL
)
515 left
= uiop
->uio_iov
->iov_len
;
521 uiocp
= uiop
->uio_iov
->iov_base
;
524 error
= md_get_mem(mdp
, uiocp
, left
, mtype
);
527 uiop
->uio_offset
+= left
;
528 uiop
->uio_resid
-= left
;
529 uiop
->uio_iov
->iov_base
=
530 (char *)uiop
->uio_iov
->iov_base
+ left
;
531 uiop
->uio_iov
->iov_len
-= left
;