* Copyright (c) 1982, 1986, 1988, 1991 Regents of the University of California.
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. All advertising materials mentioning features or use of this software
* must display the following acknowledgement:
* This product includes software developed by the University of
* California, Berkeley and its contributors.
* 4. Neither the name of the University nor the names of its contributors
* may be used to endorse or promote products derived from this software
* without specific prior written permission.
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* from: @(#)uipc_mbuf.c 7.19 (Berkeley) 4/20/91
* $Id: uipc_mbuf.c,v 1.5 1993/11/25 01:33:32 wollman Exp $
static void m_reclaim(void);
#define NCL_INIT (4096/CLBYTES)
if (m_clalloc(NCL_INIT
, M_DONTWAIT
) == 0)
* Allocate some number of mbuf clusters
* and place on cluster free list.
* Must be called at splimp.
m_clalloc(ncl
, how
) /* 31 Aug 92*/
p
= (caddr_t
)kmem_malloc(mb_map
, ctob(npg
), !(how
&M_DONTWAIT
));
log(LOG_ERR
, "mb_map full\n");
ncl
= ncl
* CLBYTES
/ MCLBYTES
;
for (i
= 0; i
< ncl
; i
++) {
((union mcluster
*)p
)->mcl_next
= mclfree
;
mclfree
= (union mcluster
*)p
;
mbstat
.m_clusters
+= ncl
;
* When MGET failes, ask protocols to free space when short of memory,
* then re-attempt to allocate an mbuf.
#define m_retry(i, t) (struct mbuf *)0
* As above; retry an MGETHDR.
#define m_retryhdr(i, t) (struct mbuf *)0
register struct domain
*dp
;
register struct protosw
*pr
;
for (dp
= domains
; dp
; dp
= dp
->dom_next
)
for (pr
= dp
->dom_protosw
; pr
< dp
->dom_protoswNPROTOSW
; pr
++)
* Space allocation routines.
* These are also available as macros
m_get(how
, type
) /* 31 Aug 92*/
m_gethdr(how
, type
) /* 31 Aug 92*/
m_getclr(how
, type
) /* 31 Aug 92*/
bzero(mtod(m
, caddr_t
), MLEN
);
* Mbuffer utility routines.
* Lesser-used path for M_PREPEND:
* allocate new mbuf to prepend to chain,
MGET(mn
, how
, m
->m_type
);
if (mn
== (struct mbuf
*)NULL
) {
return ((struct mbuf
*)NULL
);
if (m
->m_flags
& M_PKTHDR
) {
* Make a copy of an mbuf chain starting "off0" bytes from the beginning,
* continuing for "len" bytes. If len is M_COPYALL, copy to end of mbuf.
* The wait parameter is a choice of M_WAIT/M_DONTWAIT from caller.
m_copym(m
, off0
, len
, wait
)
register struct mbuf
*n
, **np
;
if (off
== 0 && m
->m_flags
& M_PKTHDR
)
MGET(n
, wait
, m
->m_type
);
n
->m_len
= MIN(len
, m
->m_len
- off
);
if (m
->m_flags
& M_EXT
) {
n
->m_data
= m
->m_data
+ off
;
mclrefcnt
[mtocl(m
->m_ext
.ext_buf
)]++;
bcopy(mtod(m
, caddr_t
)+off
, mtod(n
, caddr_t
),
* Copy data from an mbuf chain starting "off" bytes from the beginning,
* continuing for "len" bytes, into the indicated buffer.
m_copydata(m
, off
, len
, cp
)
count
= MIN(m
->m_len
- off
, len
);
bcopy(mtod(m
, caddr_t
) + off
, cp
, count
);
* Concatenate mbuf chain n to m.
* Both chains must be of the same type (e.g. MT_DATA).
* Any m_pkthdr is not updated.
register struct mbuf
*m
, *n
;
if (m
->m_flags
& M_EXT
||
m
->m_data
+ m
->m_len
+ n
->m_len
>= &m
->m_dat
[MLEN
]) {
/* just join the two chains */
/* splat the data from one into the other */
bcopy(mtod(n
, caddr_t
), mtod(m
, caddr_t
) + m
->m_len
,
register int len
= req_len
;
while (m
!= NULL
&& len
> 0) {
if (mp
->m_flags
& M_PKTHDR
)
m
->m_pkthdr
.len
-= (req_len
- len
);
* Trim from tail. Scan the mbuf chain,
* calculating its length and finding the last mbuf.
* If the adjustment only affects this mbuf, then just
* adjust and return. Otherwise, rescan and truncate
* after the remaining size.
if (m
->m_next
== (struct mbuf
*)0)
if ((mp
= m
)->m_flags
& M_PKTHDR
)
* Correct length for chain is "count".
* Find the mbuf with last data, adjust its length,
* and toss data from remaining mbufs on chain.
if (m
->m_flags
& M_PKTHDR
)
for (; m
; m
= m
->m_next
) {
* Rearange an mbuf chain so that len bytes are contiguous
* and in the data area of an mbuf (so that mtod and dtom
* will work for a structure of size len). Returns the resulting
* mbuf chain on success, frees it and returns null on failure.
* If there is room, it will add up to max_protohdr-len extra bytes to the
* contiguous region in an attempt to avoid being called next time.
* If first mbuf has no cluster, and has room for len bytes
* without shifting current data, pullup into it,
* otherwise allocate a new mbuf to prepend to the chain.
if ((n
->m_flags
& M_EXT
) == 0 &&
n
->m_data
+ len
< &n
->m_dat
[MLEN
] && n
->m_next
) {
MGET(m
, M_DONTWAIT
, n
->m_type
);
if (n
->m_flags
& M_PKTHDR
) {
space
= &m
->m_dat
[MLEN
] - (m
->m_data
+ m
->m_len
);
count
= min(min(max(len
, max_protohdr
), space
), n
->m_len
);
bcopy(mtod(n
, caddr_t
), mtod(m
, caddr_t
) + m
->m_len
,
* Copy data from a buffer back into the indicated mbuf chain,
* starting "off" bytes from the beginning, extending the mbuf
m_copyback(m0
, off
, len
, cp
)
register struct mbuf
*m
= m0
, *n
;
while (off
> (mlen
= m
->m_len
)) {
n
= m_getclr(M_DONTWAIT
, m
->m_type
);
n
->m_len
= min(MLEN
, len
+ off
);
mlen
= min (m
->m_len
- off
, len
);
bcopy(cp
, off
+ mtod(m
, caddr_t
), (unsigned)mlen
);
n
= m_get(M_DONTWAIT
, m
->m_type
);
n
->m_len
= min(MLEN
, len
);
out
: if (((m
= m0
)->m_flags
& M_PKTHDR
) && (m
->m_pkthdr
.len
< totlen
))
m
->m_pkthdr
.len
= totlen
;
register struct mbuf
*m0
;
register struct mbuf
*m
, *n
;
unsigned len
= len0
, remain
;
for (m
= m0
; m
&& len
> m
-> m_len
; m
= m
-> m_next
)
remain
= m
-> m_len
- len
;
if (m0
-> m_flags
& M_PKTHDR
) {
MGETHDR(n
, wait
, m0
-> m_type
);
n
-> m_pkthdr
.rcvif
= m0
-> m_pkthdr
.rcvif
;
n
-> m_pkthdr
.len
= m0
-> m_pkthdr
.len
- len0
;
m0
-> m_pkthdr
.len
= len0
;
if (m
-> m_flags
& M_EXT
)
/* m can't be the lead packet */
n
-> m_next
= m_split (m
, len
, wait
);
} else if (remain
== 0) {
MGET(n
, wait
, m
-> m_type
);
if (m
-> m_flags
& M_EXT
) {
mclrefcnt
[mtocl (m
-> m_ext
.ext_buf
)]++;
n
-> m_data
= m
-> m_data
+ len
;
bcopy (mtod (m
, caddr_t
) + len
, mtod (n
, caddr_t
), remain
);
n
-> m_next
= m
-> m_next
;
/* The following taken from netiso/iso_chksum.c */
m_append(head
, m
) /* XXX */
* PURPOSE: returns length of the mbuf chain.
* used all over the iso code.
m_datalen (morig
) /* XXX */
register struct mbuf
*n
=morig
;
register int datalen
= 0;
if( morig
== (struct mbuf
*)0)
if (n
->m_next
== (struct mbuf
*)0 ) {
register struct mbuf
*in
, **out
;
register int datalen
= 0;
MGET((*out
), M_DONTWAIT
, MT_DATA
);
if (in
->m_flags
& M_EXT
) {
if (((*out
)->m_flags
& M_EXT
) == 0) {
len
= M_TRAILINGSPACE(*out
);
len
= MIN(len
, in
->m_len
);
bcopy(mtod(in
, caddr_t
), mtod((*out
), caddr_t
) + (*out
)->m_len
,
if( !((*out
)->m_next
= m_get(M_DONTWAIT
, MT_DATA
))) {