* Redistribution and use in source and binary forms are permitted
* provided that the above copyright notice and this paragraph are
* duplicated in all such forms and that any documentation,
* advertising materials, and other materials related to such
* distribution and use acknowledge that the software was developed
* by the University of California, Berkeley. The name of the
* University may not be used to endorse or promote products derived
* from this software without specific prior written permission.
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
* WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
* @(#)uipc_mbuf.c 7.12 (Berkeley) %G%
#define NCL_INIT (4096/MCLBYTES)
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.
mbx
= rmalloc(mbmap
, (long)npg
);
log(LOG_ERR
, "mbuf map full\n");
p
= cltom(mbx
* NBPG
/ MCLBYTES
);
if (memall(&Mbmap
[mbx
], npg
, proc
, CSYS
) == 0) {
rmfree(mbmap
, (long)npg
, (long)mbx
);
vmaccess(&Mbmap
[mbx
], p
, npg
);
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
MGETHDR(m
, canwait
, type
);
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
,