/*-
* Copyright (c) 1982, 1986, 1988, 1991, 1993
* The Regents of the University of California. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 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
* 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
* SUCH DAMAGE.
*
* @(#)uipc_mbuf.c 8.2 (Berkeley) 1/4/94
*/
#ifndef VBOX
__FBSDID("$FreeBSD: src/sys/kern/uipc_mbuf.c,v 1.174.2.3.2.1 2009/04/15 03:14:26 kensmith Exp $");
#include "opt_mac.h"
#include "opt_param.h"
#include "opt_mbuf_stress_test.h"
int max_linkhdr;
#ifndef VBOX
int max_protohdr;
#endif
int max_hdr;
int max_datalen;
#ifdef MBUF_STRESS_TEST
int m_defragpackets;
int m_defragbytes;
int m_defraguseless;
int m_defragfailure;
#endif
/*
* sysctl(8) exported objects
*/
&max_linkhdr, 0, "Size of largest link layer header");
&max_protohdr, 0, "Size of largest protocol layer header");
&max_hdr, 0, "Size of largest link plus protocol header");
&max_datalen, 0, "Minimum space left in mbuf after max_hdr");
#ifdef MBUF_STRESS_TEST
&m_defragpackets, 0, "");
&m_defragbytes, 0, "");
&m_defraguseless, 0, "");
&m_defragfailure, 0, "");
&m_defragrandomfailures, 0, "");
#endif
#else /* VBOX */
# include "slirp.h"
#endif /* VBOX */
/*
* best) and return a pointer to the top of the allocated chain. If an
* existing mbuf chain is provided, then we will append the new chain
* to the existing one but still return the top of the newly allocated
* chain.
*/
struct mbuf *
#ifndef VBOX
#else
#endif
{
/* Validate flags. */
/* Packet header mbuf must be first in chain. */
/* Loop and append maximum sized mbufs to the chain tail. */
while (len > 0) {
#ifndef VBOX
else
/* Fail the whole operation if one mbuf can't be allocated. */
return (NULL);
}
#else
else
/* Fail the whole operation if one mbuf can't be allocated. */
return (NULL);
}
#endif
/* Book keeping. */
else
}
/* If mbuf was supplied, append new chain to the end of it. */
if (m != NULL) {
;
} else
m = nm;
return (m);
}
/*
* Free an entire chain of mbufs and associated external buffers, if
* applicable.
*/
void
#ifndef VBOX
#else
#endif
{
}
/*-
* Configure a provided mbuf to refer to the provided external storage
* buffer and setup a reference count for said buffer. If the setting
* up of the reference count fails, the M_EXT bit will not be set. If
* successfull, the M_EXT bit is set in the mbuf's flags.
*
* Arguments:
* mb The existing mbuf to which to attach the provided buffer.
* buf The address of the provided external storage buffer.
* size The size of the provided buffer.
* freef A pointer to a routine that is responsible for freeing the
* provided external storage buffer.
* args A pointer to an argument structure (of any type) to be passed
* to the provided freef routine (may be NULL).
* flags Any other flags to be passed to the provided mbuf.
* type The type that the external storage buffer should be
* labeled with.
*
* Returns:
* Nothing.
*/
void
#ifndef VBOX
#else
#endif
{
if (type != EXT_EXTREF)
}
}
/*
* Non-directly-exported function to clean up after mbufs with M_EXT
* storage attached to them if the reference count hits 1.
*/
void
#ifndef VBOX
#else
#endif
{
int skipmbuf;
/*
* check if the header is embedded in the cluster
*/
/* Free attached storage if this mbuf is the only reference to it. */
case EXT_PACKET: /* The packet zone is special. */
return; /* Job done. */
case EXT_CLUSTER:
break;
case EXT_JUMBOP:
break;
case EXT_JUMBO9:
break;
case EXT_JUMBO16:
break;
case EXT_SFBUF:
case EXT_NET_DRV:
case EXT_MOD_TYPE:
case EXT_DISPOSABLE:
#ifndef VBOX
/* This code is dead in VBOX port of BSD mbufs (probably will be used for EXT_SBUFS some day)
* @todo once bsd sbufs will be on trunk think about this code.
*/
#else
AssertMsgFailed(("unimplemented"));
#endif
/* FALLTHROUGH */
case EXT_EXTREF:
("%s: ext_free not set", __func__));
break;
default:
("%s: unknown ext_type", __func__));
}
}
if (skipmbuf)
return;
/*
* Free this mbuf back to the mbuf zone with all m_ext
* information purged.
*/
}
/*
* Attach the cluster from *m to *n, set up m_ext in *n
* and bump the refcount of the cluster.
*/
static void
{
else
}
/*
* Clean up mbuf (chain) from any tags and packet headers.
* If "all" is set then the first mbuf in the chain will be
* cleaned too.
*/
void
{
struct mbuf *m;
m_tag_delete_chain(m, NULL);
}
}
}
/*
* Sanity checks on mbuf (chain) for use in KASSERT() and general
* debugging.
* Returns 0 or panics when bad and 1 on all tests passed.
* Sanitize, 0 to run M_SANITY_ACTION, 1 to garble things so they
* blow up later.
*/
int
#ifndef VBOX
#else
#endif
{
struct mbuf *m;
caddr_t a, b;
int pktlen = 0;
#ifdef INVARIANTS
#else
#endif
/*
* Basic pointer checks. If any of these fails then some
* unrelated kernel memory before or after us is trashed.
* No way to recover from that.
*/
M_SANITY_ACTION("m_data outside mbuf data range left");
M_SANITY_ACTION("m_data outside mbuf data range right");
M_SANITY_ACTION("m_data + m_len exeeds mbuf space");
M_SANITY_ACTION("m_pkthdr.header outside mbuf data range");
}
/* m->m_nextpkt may only be set on first mbuf in chain. */
if (sanitize) {
#ifndef VBOX
#else
#endif
} else
M_SANITY_ACTION("m->m_nextpkt on in-chain mbuf");
}
/* packet length (not mbuf length!) calculation */
/* m_tags may only be attached to first mbuf in chain. */
if (sanitize) {
m_tag_delete_chain(m, NULL);
/* put in 0xDEADC0DE perhaps? */
} else
M_SANITY_ACTION("m_tags on in-chain mbuf");
}
/* M_PKTHDR may only be set on first mbuf in chain */
if (sanitize) {
/* put in 0xDEADCODE and leave hdr flag in */
} else
M_SANITY_ACTION("M_PKTHDR on in-chain mbuf");
}
}
m = m0;
if (sanitize)
else
M_SANITY_ACTION("m_pkthdr.len != mbuf chain length");
}
return 1;
}
/*
* "Move" mbuf pkthdr from "from" to "to".
* "from" must have M_PKTHDR set, and "to" must be empty.
*/
void
{
#if 0
/* see below for why these are not enabled */
/* Note: with MAC, this may not be a good assertion. */
("m_move_pkthdr: to has tags"));
#endif
#ifdef MAC
/*
* XXXMAC: It could be this should also occur for non-MAC?
*/
#endif
}
/*
* Duplicate "from"'s mbuf pkthdr in "to".
* "from" must have M_PKTHDR set, and "to" must be empty.
* In particular, this does a deep copy of the packet tags.
*/
int
{
#if 0
/*
* The mbuf allocator only initializes the pkthdr
* when the mbuf is allocated with MGETHDR. Many users
* (e.g. m_copy*, m_prepend) use MGET and then
* smash the pkthdr as needed causing these
* assertions to trip. For now just disable them.
*/
/* Note: with MAC, this may not be a good assertion. */
#endif
#ifdef MAC
#endif
}
/*
* Lesser-used path for M_PREPEND:
* allocate new mbuf to prepend to chain,
* copy junk along.
*/
struct mbuf *
#ifndef VBOX
#else
#endif
{
else
#ifndef VBOX
m_freem(m);
#else
#endif
return (NULL);
}
M_MOVE_PKTHDR(mn, m);
m = mn;
} else {
}
return (m);
}
/*
* 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_TRYWAIT/M_DONTWAIT from caller.
* Note that the copy is read-only, because clusters are not copied,
* only their reference counts are incremented.
*/
struct mbuf *
#ifndef VBOX
#else
#endif
{
int copyhdr = 0;
copyhdr = 1;
while (off > 0) {
break;
m = m->m_next;
}
top = 0;
while (len > 0) {
if (m == NULL) {
("m_copym, length > size of mbuf chain"));
break;
}
if (copyhdr)
else
*np = n;
if (n == NULL)
goto nospace;
if (copyhdr) {
if (!m_dup_pkthdr(n, m, fWait))
goto nospace;
else
copyhdr = 0;
}
mb_dupcl(n, m);
} else
off = 0;
m = m->m_next;
}
return (top);
#ifndef VBOX
#else
#endif
return (NULL);
}
/*
* Returns mbuf chain with new head for the prepending case.
* Copies from mbuf (chain) n from off for len to mbuf (chain) m
* either prepending or appending the data.
* The resulting mbuf (chain) m is fully writeable.
* m is destination (is made writeable)
* n is source, off is offset in source, len is len from offset
* dir, 0 append, 1 prepend
* how, wait or nowait
*/
static int
{
return 0;
}
struct mbuf *
#ifndef VBOX
#else
#endif
{
caddr_t p;
int i, nlen = 0;
mm = m;
if (!prep) {
}
}
return NULL;
if (!M_WRITABLE(mm)) {
/* XXX: Use proper m_xxx function instead. */
#ifndef VBOX
#else
#endif
if (x == NULL)
return NULL;
x->m_data = p;
if (mm != m)
#ifndef VBOX
#else
#endif
mm = x;
}
/*
*/
return m;
}
return mm;
}
#ifndef VBOX
#else
#endif
return NULL;
}
#ifndef VBOX
#else
#endif
return NULL;
}
return NULL;
}
return NULL;
i = 0;
if (!x->m_next)
break;
}
m_move_pkthdr(mm, z);
mm = z;
}
/* Seek to start position in source mbuf. Optimization for long chains. */
while (off > 0) {
break;
n = n->m_next;
}
/* Copy data into target mbuf. */
z = mm;
while (len > 0) {
i = M_TRAILINGSPACE(z);
z->m_len += i;
/* fixup pkthdr.len if necessary */
off += i;
len -= i;
z = z->m_next;
}
}
/*
* Copy an entire packet, including header (which must be present).
* An optimization of the common case `m_copym(m, 0, M_COPYALL, how)'.
* Note that the copy is read-only, because clusters are not copied,
* only their reference counts are incremented.
* Preserve alignment of the first mbuf so if the creator has left
* some room at the beginning (e.g. for inserting protocol headers)
* the copies still have the room available.
*/
struct mbuf *
#ifndef VBOX
#else
#endif
{
top = n;
if (n == NULL)
goto nospace;
if (!m_dup_pkthdr(n, m, how))
goto nospace;
mb_dupcl(n, m);
} else {
}
m = m->m_next;
while (m) {
if (o == NULL)
goto nospace;
n->m_next = o;
n = n->m_next;
mb_dupcl(n, m);
} else {
}
m = m->m_next;
}
return top;
#ifndef VBOX
#else
#endif
return (NULL);
}
/*
* Copy data from an mbuf chain starting "off" bytes from the beginning,
* continuing for "len" bytes, into the indicated buffer.
*/
void
{
while (off > 0) {
break;
m = m->m_next;
}
while (len > 0) {
off = 0;
m = m->m_next;
}
}
/*
* Copy a packet header mbuf chain into a completely new chain, including
* copying any mbuf clusters. Use this instead of m_copypacket() when
* you need a writable copy of an mbuf chain.
*/
struct mbuf *
#ifndef VBOX
#else
#endif
{
/* Sanity check */
if (m == NULL)
return (NULL);
M_ASSERTPKTHDR(m);
/* While there's more data, get a new mbuf, tack it on, and fill it */
moff = 0;
p = ⊤
struct mbuf *n;
/* Get the next new mbuf */
#ifndef VBOX
#else
#endif
} else {
#ifndef VBOX
#else
#endif
}
if (n == NULL)
goto nospace;
if (!m_dup_pkthdr(n, m, how)) {
#ifndef VBOX
m_free(n);
#else
#endif
goto nospace;
}
}
n->m_len = 0;
/* Link it into the new chain */
*p = n;
p = &n->m_next;
/* Copy data from original mbuf(s) into new mbuf */
m = m->m_next;
moff = 0;
}
}
/* Check correct total mbuf length */
("%s: bogus m_pkthdr.len", __func__));
}
return (top);
#ifndef VBOX
#else
#endif
return (NULL);
}
/*
* Concatenate mbuf chain n to m.
* Both chains must be of the same type (e.g. MT_DATA).
* Any m_pkthdr is not updated.
*/
void
#ifndef VBOX
#else
#endif
{
while (m->m_next)
m = m->m_next;
while (n) {
/* just join the two chains */
m->m_next = n;
return;
}
/* splat the data from one into the other */
#ifndef VBOX
n = m_free(n);
#else
#endif
}
}
void
#ifndef VBOX
#else
#endif
{
struct mbuf *m;
int count;
return;
if (len >= 0) {
/*
* Trim from head.
*/
m->m_len = 0;
m = m->m_next;
} else {
len = 0;
}
}
m = mp;
} else {
/*
* 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.
*/
count = 0;
for (;;) {
break;
m = m->m_next;
}
return;
}
if (count < 0)
count = 0;
/*
* Correct length for chain is "count".
* Find the mbuf with last data, adjust its length,
* and toss data from remaining mbufs on chain.
*/
m = mp;
for (; m; m = m->m_next) {
#ifndef VBOX
#else
#endif
}
break;
}
}
}
}
/*
* 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.
*/
struct mbuf *
#ifndef VBOX
#else
#endif
{
struct mbuf *m;
int count;
int space;
/*
* 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.
*/
return (n);
m = n;
n = n->m_next;
} else {
goto bad;
if (m == NULL)
goto bad;
m->m_len = 0;
M_MOVE_PKTHDR(m, n);
}
do {
if (n->m_len)
else
#ifndef VBOX
n = m_free(n);
#else
#endif
} while (len > 0 && n);
if (len > 0) {
#ifndef VBOX
(void) m_free(m);
#else
#endif
goto bad;
}
m->m_next = n;
return (m);
bad:
#ifndef VBOX
m_freem(n);
#else
#endif
return (NULL);
}
/*
* Like m_pullup(), except a new mbuf is always allocated, and we allow
* the amount of empty space before the data in the new mbuf to be specified
* (in the event that the caller expects to prepend later).
*/
int MSFail;
struct mbuf *
#ifndef VBOX
#else
#endif
{
struct mbuf *m;
goto bad;
if (m == NULL)
goto bad;
m->m_len = 0;
M_MOVE_PKTHDR(m, n);
do {
(unsigned)count);
if (n->m_len)
else
#ifndef VBOX
n = m_free(n);
#else
#endif
} while (len > 0 && n);
if (len > 0) {
#ifndef VBOX
(void) m_free(m);
#else
#endif
goto bad;
}
m->m_next = n;
return (m);
bad:
#ifndef VBOX
m_freem(n);
#else
#endif
MSFail++;
return (NULL);
}
/*
* Partition an mbuf chain in two pieces, returning the tail --
* all but the first len0 bytes. In case of failure, it returns NULL and
* attempts to restore the chain to its original state.
*
* Note that the resulting mbufs might be read-only, because the new
* mbuf can end up sharing an mbuf cluster with the original mbuf if
* the "breaking point" happens to lie within a cluster mbuf. Use the
* M_WRITABLE() macro to check for this case.
*/
struct mbuf *
#ifndef VBOX
#else
#endif
{
struct mbuf *m, *n;
if (m == NULL)
return (NULL);
if (n == NULL)
return (NULL);
goto extpacket;
/* m can't be the lead packet */
MH_ALIGN(n, 0);
#ifndef VBOX
#else
#endif
#ifndef VBOX
(void) m_free(n);
#else
#endif
return (NULL);
} else {
n->m_len = 0;
return (n);
}
} else
} else if (remain == 0) {
n = m->m_next;
return (n);
} else {
if (n == NULL)
return (NULL);
}
mb_dupcl(n, m);
} else {
}
return (n);
}
/*
* Routine to copy from device local memory into mbufs.
* Note that `off' argument is offset into first mbuf of target chain from
* which to begin copying the data to.
*/
#ifndef VBOX
struct mbuf *
{
struct mbuf *m;
int len;
return (NULL);
while (totlen > 0) {
} else {
m->m_data += max_linkhdr;
len -= max_linkhdr;
}
}
if (m == NULL)
return NULL;
} else {
} else {
}
if (m == NULL) {
return NULL;
}
}
if (off) {
off = 0;
}
if (copy)
else
*mp = m;
}
return (top);
}
#endif
/*
* Copy data from a buffer back into the indicated mbuf chain,
* starting "off" bytes from the beginning, extending the mbuf
* chain if necessary.
*/
void
#ifndef VBOX
#else
#endif
{
int mlen;
int totlen = 0;
return;
#ifndef VBOX
#else
#endif
if (n == NULL)
goto out;
m->m_next = n;
}
m = m->m_next;
}
while (len > 0) {
M_TRAILINGSPACE(m));
}
off = 0;
if (len == 0)
break;
#ifndef VBOX
#else
#endif
if (n == NULL)
break;
m->m_next = n;
}
m = m->m_next;
}
}
/*
* Append the specified data to the indicated mbuf chain,
* Extend the mbuf chain if the new data does not fit in
* existing space.
*
* Return 1 if able to complete the job; otherwise 0.
*/
int
#ifndef VBOX
#else
#endif
{
struct mbuf *m, *n;
;
space = M_TRAILINGSPACE(m);
if (space > 0) {
/*
* Copy into available space.
*/
}
while (remainder > 0) {
/*
* Allocate a new mbuf; could check space
* and allocate a cluster instead.
*/
#ifndef VBOX
#else
#endif
if (n == NULL)
break;
m->m_next = n;
m = n;
}
return (remainder == 0);
}
/*
* Apply function f to the data in an mbuf chain starting "off" bytes from
* the beginning, continuing for "len" bytes.
*/
int
{
int rval;
while (off > 0) {
break;
m = m->m_next;
}
while (len > 0) {
if (rval)
return (rval);
off = 0;
m = m->m_next;
}
return (0);
}
/*
*/
struct mbuf *
{
while (loc >= 0) {
/* Normal end of search. */
return (m);
} else {
if (loc == 0) {
/* Point at the end of valid data. */
return (m);
}
return (NULL);
}
m = m->m_next;
}
}
return (NULL);
}
void
{
int len;
int pdata;
else
len = -1;
m2 = m;
"\11proto5\10proto4\7proto3\6proto2\5proto1\4rdonly"
if (pdata)
if (len != -1)
}
if (len > 0)
return;
}
{
return (len);
}
{
struct mbuf *m;
len = 0;
break;
}
*last = m;
return (len);
}
/*
* Defragment a mbuf chain, returning the shortest possible
* chain of mbufs and clusters. If allocation fails and
* this cannot be completed, NULL will be returned, but
* the passed in chain will be unchanged. Upon success,
* the original chain will be freed, and the new chain
* will be returned.
*
* If a non-packet header is passed in, the original
* mbuf (chain?) will be returned unharmed.
*/
struct mbuf *
#ifndef VBOX
#else
#endif
{
return (m0);
#ifdef MBUF_STRESS_TEST
if (m_defragrandomfailures) {
if (temp == 0xba)
goto nospace;
}
#endif
#ifndef VBOX
#else
#endif
else
#ifndef VBOX
#else
#endif
goto nospace;
goto nospace;
#ifndef VBOX
#else
#endif
else
#ifndef VBOX
#else
#endif
goto nospace;
}
#ifndef VBOX
#else
#endif
}
#ifdef MBUF_STRESS_TEST
#endif
#ifndef VBOX
#else
#endif
#ifdef MBUF_STRESS_TEST
#endif
return (m0);
#ifdef MBUF_STRESS_TEST
#endif
if (m_final)
#ifndef VBOX
#else
#endif
return (NULL);
}
/*
* Defragment an mbuf chain, returning at most maxfrags separate
* mbufs+clusters. If this is not possible NULL is returned and
* the original mbuf chain is left in it's present (potentially
* modified) state. We use two techniques: collapsing consecutive
* mbufs and replacing consecutive mbufs by a cluster.
*
* NB: this should really be named m_defrag but that name is taken
*/
struct mbuf *
#ifndef VBOX
#else
#endif
{
/*
* Calculate the current number of frags.
*/
curfrags = 0;
curfrags++;
/*
* First, try to collapse mbufs. Note that we always collapse
* towards the front so we don't need to deal with moving the
* pkthdr. This may be suboptimal if the first mbuf has much
* less data than the following.
*/
m = m0;
for (;;) {
n = m->m_next;
if (n == NULL)
break;
n->m_len < M_TRAILINGSPACE(m)) {
n->m_len);
#ifndef VBOX
m_free(n);
#else
#endif
return m0;
} else
m = n;
}
("maxfrags %u, but normal collapse failed", maxfrags));
/*
* Collapse consecutive mbufs to a cluster.
*/
#ifndef VBOX
#else
#endif
if (m == NULL)
goto bad;
*prev = m;
#ifndef VBOX
m_free(n);
#else
#endif
return m0;
/*
* Still not there, try the normal collapse
* again before we allocate another cluster.
*/
goto again;
}
}
/*
* No place where we can collapse to a cluster; punt.
* This can occur if, for example, you request 2 frags
* but the packet requires that both be clusters (we
* never reallocate the first mbuf to avoid moving the
* packet header).
*/
bad:
return NULL;
}
#ifdef MBUF_STRESS_TEST
/*
* Fragment an mbuf chain. There's no reason you'd ever want to do
* this in normal usage, but it's great for stress testing various
* mbuf consumers.
*
* If fragmentation is not possible, the original chain will be
* returned.
*
* Possible length values:
* 0 no fragmentation will occur
* > 0 each fragment will be of the specified length
* -1 each fragment will be the same random value in length
* -2 each fragment's length will be entirely random
* (Random values range from 1 to 256)
*/
struct mbuf *
{
int progress = 0;
return (m0);
return (m0);
goto nospace;
goto nospace;
if (length == -1)
int fraglen;
if (length > 0)
else
goto nospace;
}
}
return (m0);
if (m_final)
/* Return the original chain on failure */
return (m0);
}
#endif
/*
* Copy the contents of uio into a properly sized mbuf chain.
*/
#ifndef VBOX
struct mbuf *
{
int progress = 0;
/*
* len can be zero or an arbitrary large value bound by
* the total data supplied by the uio.
*/
if (len > 0)
else
/*
* The smallest unit returned by m_getm2() is a single mbuf
* with pkthdr. We can't align past it.
*/
return (NULL);
/*
* Give us the full allocation or nothing.
* If len is zero return the smallest empty mbuf.
*/
if (m == NULL)
return (NULL);
/* Fill all mbufs with uio data and update header information. */
if (error) {
m_freem(m);
return (NULL);
}
}
return (m);
}
#endif
/*
* Set the m_data pointer of a newly-allocated mbuf
* to place an object of the specified size at the
* end of the mbuf, longword aligned.
*/
void
{
int adjust;
else
}
/*
* Create a writable copy of the mbuf chain. While doing this
* we compact the chain with a goal of producing a chain with
* at most two mbufs. The second mbuf in this chain is likely
* to be a cluster. The primary purpose of this work is to create
* a writable packet for encryption, compression, etc. The
* secondary goal is to linearize the data so the data can be
* passed to crypto hardware in the most efficient manner possible.
*/
struct mbuf *
#ifndef VBOX
#else
#endif
{
/*
* Regular mbufs are ignored unless there's a cluster
* in front of it that we can use to coalesce. We do
* the latter mainly so later clusters can be coalesced
* also w/o having to handle them specially (i.e. convert
* mbuf+cluster -> cluster). This optimization is heavily
* influenced by the assumption that we're running over
* Ethernet where MCLBYTES is large enough that the max
* packet size will permit lots of coalescing into a
* single cluster. This in turn permits efficient
* crypto operations, especially when using hardware.
*/
/* XXX: this ignores mbuf types */
#ifndef VBOX
m_free(m); /* reclaim mbuf */
#else
#endif
#if 0
#endif
} else {
mprev = m;
}
continue;
}
/*
* Writable mbufs are left alone (for now).
*/
if (M_WRITABLE(m)) {
mprev = m;
continue;
}
/*
* Not writable, replace with a copy or coalesce with
* the previous mbuf if possible (since we have to copy
* it anyway, we try to reduce the number of mbufs and
* clusters so that future work is easier).
*/
/* NB: we only coalesce into a cluster or larger */
/* XXX: this ignores mbuf types */
#ifndef VBOX
m_free(m); /* reclaim mbuf */
#else
#endif
#if 0
#endif
continue;
}
/*
* Allocate new space to hold the copy...
*/
/* XXX why can M_PKTHDR be set past the first mbuf? */
/*
* NB: if a packet header is present we must
* allocate the mbuf separately from any cluster
* because M_MOVE_PKTHDR will smash the data
* pointer and drop the M_EXT marker.
*/
if (n == NULL) {
#ifndef VBOX
#else
#endif
return (NULL);
}
M_MOVE_PKTHDR(n, m);
#ifndef VBOX
m_free(n);
#else
#endif
return (NULL);
}
} else {
#ifndef VBOX
#else
#endif
if (n == NULL) {
#ifndef VBOX
#else
#endif
return (NULL);
}
}
/*
* ... and copy the data. We deal with jumbo mbufs
* (i.e. m_len > MCLBYTES) by splitting them into
* clusters. We could just malloc a buffer and make
* it external but too many device drivers don't know
* how to break up the non-contiguous memory when
* doing DMA.
*/
off = 0;
mfirst = n;
for (;;) {
mlast = n;
#if 0
#endif
if (len <= 0)
break;
#ifndef VBOX
#else
#endif
if (n == NULL) {
#ifndef VBOX
#else
#endif
return (NULL);
}
}
else
#ifndef VBOX
m_free(m); /* release old mbuf */
#else
#endif
}
return (m0);
}