Index: trunk/src/VBox/Devices/Network/slirp/bsd/amd64/in_cksum.c
===================================================================
--- trunk/src/VBox/Devices/Network/slirp/bsd/amd64/in_cksum.c	(revision 27869)
+++ trunk/src/VBox/Devices/Network/slirp/bsd/amd64/in_cksum.c	(revision 27869)
@@ -0,0 +1,249 @@
+/* $NetBSD: in_cksum.c,v 1.7 1997/09/02 13:18:15 thorpej Exp $ */
+
+/*-
+ * Copyright (c) 1988, 1992, 1993
+ *	The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 1996
+ *	Matt Thomas <matt@3am-software.com>
+ *
+ * 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
+ *    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
+ * SUCH DAMAGE.
+ *
+ *	@(#)in_cksum.c	8.1 (Berkeley) 6/10/93
+ */
+
+#ifndef VBOX
+#include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
+__FBSDID("$FreeBSD: src/sys/amd64/amd64/in_cksum.c,v 1.5.20.1 2009/04/15 03:14:26 kensmith Exp $");
+
+#include <sys/param.h>
+#include <sys/mbuf.h>
+#include <sys/systm.h>
+#include <netinet/in_systm.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <machine/in_cksum.h>
+#else
+# include "in_cksum.h"
+# include "slirp.h"
+# ifndef u_int64_t
+typedef uint64_t u_int64_t;
+# endif
+#endif
+
+/*
+ * Checksum routine for Internet Protocol family headers
+ *    (Portable Alpha version).
+ *
+ * This routine is very heavily used in the network
+ * code and should be modified for each CPU to be as fast as possible.
+ */
+
+#define ADDCARRY(x)  (x > 65535 ? x -= 65535 : x)
+#define REDUCE32							  \
+    {									  \
+	q_util.q = sum;							  \
+	sum = q_util.s[0] + q_util.s[1] + q_util.s[2] + q_util.s[3];	  \
+    }
+#define REDUCE16							  \
+    {									  \
+	q_util.q = sum;							  \
+	l_util.l = q_util.s[0] + q_util.s[1] + q_util.s[2] + q_util.s[3]; \
+	sum = l_util.s[0] + l_util.s[1];				  \
+	ADDCARRY(sum);							  \
+    }
+
+static const u_int32_t in_masks[] = {
+	/*0 bytes*/ /*1 byte*/	/*2 bytes*/ /*3 bytes*/
+	0x00000000, 0x000000FF, 0x0000FFFF, 0x00FFFFFF,	/* offset 0 */
+	0x00000000, 0x0000FF00, 0x00FFFF00, 0xFFFFFF00,	/* offset 1 */
+	0x00000000, 0x00FF0000, 0xFFFF0000, 0xFFFF0000,	/* offset 2 */
+	0x00000000, 0xFF000000, 0xFF000000, 0xFF000000,	/* offset 3 */
+};
+
+union l_util {
+	u_int16_t s[2];
+	u_int32_t l;
+};
+union q_util {
+	u_int16_t s[4];
+	u_int32_t l[2];
+	u_int64_t q;
+};
+
+static u_int64_t
+in_cksumdata(const void *buf, int len)
+{
+	const u_int32_t *lw = (const u_int32_t *) buf;
+	u_int64_t sum = 0;
+	u_int64_t prefilled;
+	int offset;
+	union q_util q_util;
+
+	if ((3 & (long) lw) == 0 && len == 20) {
+	     sum = (u_int64_t) lw[0] + lw[1] + lw[2] + lw[3] + lw[4];
+	     REDUCE32;
+	     return sum;
+	}
+
+	if ((offset = 3 & (long) lw) != 0) {
+		const u_int32_t *masks = in_masks + (offset << 2);
+		lw = (u_int32_t *) (((long) lw) - offset);
+		sum = *lw++ & masks[len >= 3 ? 3 : len];
+		len -= 4 - offset;
+		if (len <= 0) {
+			REDUCE32;
+			return sum;
+		}
+	}
+#if 0
+	/*
+	 * Force to cache line boundary.
+	 */
+	offset = 32 - (0x1f & (long) lw);
+	if (offset < 32 && len > offset) {
+		len -= offset;
+		if (4 & offset) {
+			sum += (u_int64_t) lw[0];
+			lw += 1;
+		}
+		if (8 & offset) {
+			sum += (u_int64_t) lw[0] + lw[1];
+			lw += 2;
+		}
+		if (16 & offset) {
+			sum += (u_int64_t) lw[0] + lw[1] + lw[2] + lw[3];
+			lw += 4;
+		}
+	}
+#endif
+	/*
+	 * access prefilling to start load of next cache line.
+	 * then add current cache line
+	 * save result of prefilling for loop iteration.
+	 */
+	prefilled = lw[0];
+	while ((len -= 32) >= 4) {
+		u_int64_t prefilling = lw[8];
+		sum += prefilled + lw[1] + lw[2] + lw[3]
+			+ lw[4] + lw[5] + lw[6] + lw[7];
+		lw += 8;
+		prefilled = prefilling;
+	}
+	if (len >= 0) {
+		sum += prefilled + lw[1] + lw[2] + lw[3]
+			+ lw[4] + lw[5] + lw[6] + lw[7];
+		lw += 8;
+	} else {
+		len += 32;
+	}
+	while ((len -= 16) >= 0) {
+		sum += (u_int64_t) lw[0] + lw[1] + lw[2] + lw[3];
+		lw += 4;
+	}
+	len += 16;
+	while ((len -= 4) >= 0) {
+		sum += (u_int64_t) *lw++;
+	}
+	len += 4;
+	if (len > 0)
+		sum += (u_int64_t) (in_masks[len] & *lw);
+	REDUCE32;
+	return sum;
+}
+
+u_short
+in_addword(u_short a, u_short b)
+{
+	u_int64_t sum = a + b;
+
+	ADDCARRY(sum);
+	return (sum);
+}
+
+u_short
+in_pseudo(u_int32_t a, u_int32_t b, u_int32_t c)
+{
+	u_int64_t sum;
+	union q_util q_util;
+	union l_util l_util;
+
+	sum = (u_int64_t) a + b + c;
+	REDUCE16;
+	return (sum);
+}
+
+u_short
+in_cksum_skip(struct mbuf *m, int len, int skip)
+{
+	u_int64_t sum = 0;
+	int mlen = 0;
+	int clen = 0;
+	caddr_t addr;
+	union q_util q_util;
+	union l_util l_util;
+
+        len -= skip;
+        for (; skip && m; m = m->m_next) {
+                if (m->m_len > skip) {
+                        mlen = m->m_len - skip;
+			addr = mtod(m, caddr_t) + skip;
+                        goto skip_start;
+                } else {
+                        skip -= m->m_len;
+                }
+        }
+
+	for (; m && len; m = m->m_next) {
+		if (m->m_len == 0)
+			continue;
+		mlen = m->m_len;
+		addr = mtod(m, caddr_t);
+skip_start:
+		if (len < mlen)
+			mlen = len;
+		if ((clen ^ (long) addr) & 1)
+		    sum += in_cksumdata(addr, mlen) << 8;
+		else
+		    sum += in_cksumdata(addr, mlen);
+
+		clen += mlen;
+		len -= mlen;
+	}
+	REDUCE16;
+	return (~sum & 0xffff);
+}
+
+u_int in_cksum_hdr(const struct ip *ip)
+{
+    u_int64_t sum = in_cksumdata(ip, sizeof(struct ip));
+    union q_util q_util;
+    union l_util l_util;
+    REDUCE16;
+    return (~sum & 0xffff);
+}
Index: trunk/src/VBox/Devices/Network/slirp/bsd/amd64/include/in_cksum.h
===================================================================
--- trunk/src/VBox/Devices/Network/slirp/bsd/amd64/include/in_cksum.h	(revision 27869)
+++ trunk/src/VBox/Devices/Network/slirp/bsd/amd64/include/in_cksum.h	(revision 27869)
@@ -0,0 +1,84 @@
+/*-
+ * Copyright (c) 1990 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
+ *    documentation and/or other materials provided with the distribution.
+ * 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.
+ *
+ *	from tahoe:	in_cksum.c	1.2	86/01/05
+ *	from:		@(#)in_cksum.c	1.3 (Berkeley) 1/19/91
+ *	from: Id: in_cksum.c,v 1.8 1995/12/03 18:35:19 bde Exp
+ * $FreeBSD: src/sys/amd64/include/in_cksum.h,v 1.5.20.1 2009/04/15 03:14:26 kensmith Exp $
+ */
+
+#ifndef _MACHINE_IN_CKSUM_H_
+#define	_MACHINE_IN_CKSUM_H_	1
+
+#ifndef VBOX
+#ifndef _SYS_CDEFS_H_
+#error this file needs sys/cdefs.h as a prerequisite
+#endif
+
+#include <sys/cdefs.h>
+#else
+# include "slirp.h"
+#endif
+
+#define in_cksum(m, len)	in_cksum_skip(m, len, 0)
+
+/*
+ * It it useful to have an Internet checksum routine which is inlineable
+ * and optimized specifically for the task of computing IP header checksums
+ * in the normal case (where there are no options and the header length is
+ * therefore always exactly five 32-bit words.
+ */
+#ifdef __CC_SUPPORTS___INLINE
+
+static __inline void
+in_cksum_update(struct ip *ip)
+{
+	int __tmpsum;
+	__tmpsum = (int)ntohs(ip->ip_sum) + 256;
+	ip->ip_sum = htons(__tmpsum + (__tmpsum >> 16));
+}
+
+#else
+
+#define	in_cksum_update(ip) \
+	do { \
+		int __tmpsum; \
+		__tmpsum = (int)ntohs(ip->ip_sum) + 256; \
+		ip->ip_sum = htons(__tmpsum + (__tmpsum >> 16)); \
+	} while(0)
+
+#endif
+
+#ifdef _KERNEL
+u_int in_cksum_hdr(const struct ip *ip);
+u_short	in_addword(u_short sum, u_short b);
+u_short	in_pseudo(u_int sum, u_int b, u_int c);
+u_short	in_cksum_skip(struct mbuf *m, int len, int skip);
+#endif
+
+#endif /* _MACHINE_IN_CKSUM_H_ */
Index: trunk/src/VBox/Devices/Network/slirp/bsd/i386/in_cksum.c
===================================================================
--- trunk/src/VBox/Devices/Network/slirp/bsd/i386/in_cksum.c	(revision 27869)
+++ trunk/src/VBox/Devices/Network/slirp/bsd/i386/in_cksum.c	(revision 27869)
@@ -0,0 +1,499 @@
+/*-
+ * Copyright (c) 1990 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
+ *    documentation and/or other materials provided with the distribution.
+ * 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.
+ *
+ *	from tahoe:	in_cksum.c	1.2	86/01/05
+ *	from:		@(#)in_cksum.c	1.3 (Berkeley) 1/19/91
+ */
+
+#ifndef VBOX
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/i386/i386/in_cksum.c,v 1.28.10.1.6.1 2009/04/15 03:14:26 kensmith Exp $");
+
+/*
+ * MPsafe: alfred
+ */
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+
+#include <netinet/in.h>
+#include <netinet/in_systm.h>
+#include <netinet/ip.h>
+
+#include <machine/in_cksum.h>
+#else
+# include "in_cksum.h"
+# include "slirp.h"
+#endif
+
+/*
+ * Checksum routine for Internet Protocol family headers.
+ *
+ * This routine is very heavily used in the network
+ * code and should be modified for each CPU to be as fast as possible.
+ *
+ * This implementation is 386 version.
+ */
+
+#undef	ADDCARRY
+#define ADDCARRY(x)     if ((x) > 0xffff) (x) -= 0xffff
+/*
+ * icc needs to be special cased here, as the asm code below results
+ * in broken code if compiled with icc.
+ */
+#if !defined(__GNUCLIKE_ASM) || defined(__INTEL_COMPILER)
+/* non gcc parts stolen from sys/alpha/alpha/in_cksum.c */
+#define REDUCE32							  \
+    {									  \
+	q_util.q = sum;							  \
+	sum = q_util.s[0] + q_util.s[1] + q_util.s[2] + q_util.s[3];	  \
+    }
+#define REDUCE16							  \
+    {									  \
+	q_util.q = sum;							  \
+	l_util.l = q_util.s[0] + q_util.s[1] + q_util.s[2] + q_util.s[3]; \
+	sum = l_util.s[0] + l_util.s[1];				  \
+	ADDCARRY(sum);							  \
+    }
+#endif
+#define REDUCE          {sum = (sum & 0xffff) + (sum >> 16); ADDCARRY(sum);}
+
+#if !defined(__GNUCLIKE_ASM) || defined(__INTEL_COMPILER)
+static const u_int32_t in_masks[] = {
+	/*0 bytes*/ /*1 byte*/	/*2 bytes*/ /*3 bytes*/
+	0x00000000, 0x000000FF, 0x0000FFFF, 0x00FFFFFF,	/* offset 0 */
+	0x00000000, 0x0000FF00, 0x00FFFF00, 0xFFFFFF00,	/* offset 1 */
+	0x00000000, 0x00FF0000, 0xFFFF0000, 0xFFFF0000,	/* offset 2 */
+	0x00000000, 0xFF000000, 0xFF000000, 0xFF000000,	/* offset 3 */
+};
+
+union l_util {
+	u_int16_t s[2];
+	u_int32_t l;
+};
+union q_util {
+	u_int16_t s[4];
+	u_int32_t l[2];
+	u_int64_t q;
+};
+
+static u_int64_t
+in_cksumdata(const u_int32_t *lw, int len)
+{
+	u_int64_t sum = 0;
+	u_int64_t prefilled;
+	int offset;
+	union q_util q_util;
+
+	if ((3 & (long) lw) == 0 && len == 20) {
+	     sum = (u_int64_t) lw[0] + lw[1] + lw[2] + lw[3] + lw[4];
+	     REDUCE32;
+	     return sum;
+	}
+
+	if ((offset = 3 & (long) lw) != 0) {
+		const u_int32_t *masks = in_masks + (offset << 2);
+		lw = (u_int32_t *) (((long) lw) - offset);
+		sum = *lw++ & masks[len >= 3 ? 3 : len];
+		len -= 4 - offset;
+		if (len <= 0) {
+			REDUCE32;
+			return sum;
+		}
+	}
+#if 0
+	/*
+	 * Force to cache line boundary.
+	 */
+	offset = 32 - (0x1f & (long) lw);
+	if (offset < 32 && len > offset) {
+		len -= offset;
+		if (4 & offset) {
+			sum += (u_int64_t) lw[0];
+			lw += 1;
+		}
+		if (8 & offset) {
+			sum += (u_int64_t) lw[0] + lw[1];
+			lw += 2;
+		}
+		if (16 & offset) {
+			sum += (u_int64_t) lw[0] + lw[1] + lw[2] + lw[3];
+			lw += 4;
+		}
+	}
+#endif
+	/*
+	 * access prefilling to start load of next cache line.
+	 * then add current cache line
+	 * save result of prefilling for loop iteration.
+	 */
+	prefilled = lw[0];
+	while ((len -= 32) >= 4) {
+		u_int64_t prefilling = lw[8];
+		sum += prefilled + lw[1] + lw[2] + lw[3]
+			+ lw[4] + lw[5] + lw[6] + lw[7];
+		lw += 8;
+		prefilled = prefilling;
+	}
+	if (len >= 0) {
+		sum += prefilled + lw[1] + lw[2] + lw[3]
+			+ lw[4] + lw[5] + lw[6] + lw[7];
+		lw += 8;
+	} else {
+		len += 32;
+	}
+	while ((len -= 16) >= 0) {
+		sum += (u_int64_t) lw[0] + lw[1] + lw[2] + lw[3];
+		lw += 4;
+	}
+	len += 16;
+	while ((len -= 4) >= 0) {
+		sum += (u_int64_t) *lw++;
+	}
+	len += 4;
+	if (len > 0)
+		sum += (u_int64_t) (in_masks[len] & *lw);
+	REDUCE32;
+	return sum;
+}
+
+u_short
+in_addword(u_short a, u_short b)
+{
+	u_int64_t sum = a + b;
+
+	ADDCARRY(sum);
+	return (sum);
+}
+
+u_short
+in_pseudo(u_int32_t a, u_int32_t b, u_int32_t c)
+{
+	u_int64_t sum;
+	union q_util q_util;
+	union l_util l_util;
+
+	sum = (u_int64_t) a + b + c;
+	REDUCE16;
+	return (sum);
+}
+
+u_short
+in_cksum_skip(struct mbuf *m, int len, int skip)
+{
+	u_int64_t sum = 0;
+	int mlen = 0;
+	int clen = 0;
+	caddr_t addr;
+	union q_util q_util;
+	union l_util l_util;
+
+        len -= skip;
+        for (; skip && m; m = m->m_next) {
+                if (m->m_len > skip) {
+                        mlen = m->m_len - skip;
+			addr = mtod(m, caddr_t) + skip;
+                        goto skip_start;
+                } else {
+                        skip -= m->m_len;
+                }
+        }
+
+	for (; m && len; m = m->m_next) {
+		if (m->m_len == 0)
+			continue;
+		mlen = m->m_len;
+		addr = mtod(m, caddr_t);
+skip_start:
+		if (len < mlen)
+			mlen = len;
+		if ((clen ^ (long) addr) & 1)
+		    sum += in_cksumdata((const u_int32_t *)addr, mlen) << 8;
+		else
+		    sum += in_cksumdata((const u_int32_t *)addr, mlen);
+
+		clen += mlen;
+		len -= mlen;
+	}
+	REDUCE16;
+	return (~sum & 0xffff);
+}
+
+u_int in_cksum_hdr(const struct ip *ip)
+{
+    u_int64_t sum = in_cksumdata((const u_int32_t *)ip, sizeof(struct ip));
+    union q_util q_util;
+    union l_util l_util;
+
+    REDUCE16;
+    return (~sum & 0xffff);
+}
+#else
+
+/*
+ * These asm statements require __volatile because they pass information
+ * via the condition codes.  GCC does not currently provide a way to specify
+ * the condition codes as an input or output operand.
+ *
+ * The LOAD macro below is effectively a prefetch into cache.  GCC will
+ * load the value into a register but will not use it.  Since modern CPUs
+ * reorder operations, this will generally take place in parallel with
+ * other calculations.
+ */
+u_short
+in_cksum_skip(m, len, skip)
+	struct mbuf *m;
+	int len;
+	int skip;
+{
+	register u_short *w;
+	register unsigned sum = 0;
+	register int mlen = 0;
+	int byte_swapped = 0;
+	union { char	c[2]; u_short	s; } su;
+
+	len -= skip;
+	for (; skip && m; m = m->m_next) {
+		if (m->m_len > skip) {
+			mlen = m->m_len - skip;
+			w = (u_short *)(mtod(m, u_char *) + skip);
+			goto skip_start;
+		} else {
+			skip -= m->m_len;
+		}
+	}
+
+	for (;m && len; m = m->m_next) {
+		if (m->m_len == 0)
+			continue;
+		w = mtod(m, u_short *);
+		if (mlen == -1) {
+			/*
+			 * The first byte of this mbuf is the continuation
+			 * of a word spanning between this mbuf and the
+			 * last mbuf.
+			 */
+
+			/* su.c[0] is already saved when scanning previous
+			 * mbuf.  sum was REDUCEd when we found mlen == -1
+			 */
+			su.c[1] = *(u_char *)w;
+			sum += su.s;
+			w = (u_short *)((char *)w + 1);
+			mlen = m->m_len - 1;
+			len--;
+		} else
+			mlen = m->m_len;
+skip_start:
+		if (len < mlen)
+			mlen = len;
+		len -= mlen;
+		/*
+		 * Force to long boundary so we do longword aligned
+		 * memory operations
+		 */
+		if (3 & (int) w) {
+			REDUCE;
+			if ((1 & (int) w) && (mlen > 0)) {
+				sum <<= 8;
+				su.c[0] = *(char *)w;
+				w = (u_short *)((char *)w + 1);
+				mlen--;
+				byte_swapped = 1;
+			}
+			if ((2 & (int) w) && (mlen >= 2)) {
+				sum += *w++;
+				mlen -= 2;
+			}
+		}
+		/*
+		 * Advance to a 486 cache line boundary.
+		 */
+		if (4 & (int) w && mlen >= 4) {
+			__asm __volatile (
+				"addl %1, %0\n"
+				"adcl $0, %0"
+				: "+r" (sum)
+				: "g" (((const u_int32_t *)w)[0])
+			);
+			w += 2;
+			mlen -= 4;
+		}
+		if (8 & (int) w && mlen >= 8) {
+			__asm __volatile (
+				"addl %1, %0\n"
+				"adcl %2, %0\n"
+				"adcl $0, %0"
+				: "+r" (sum)
+				: "g" (((const u_int32_t *)w)[0]),
+				  "g" (((const u_int32_t *)w)[1])
+			);
+			w += 4;
+			mlen -= 8;
+		}
+		/*
+		 * Do as much of the checksum as possible 32 bits at at time.
+		 * In fact, this loop is unrolled to make overhead from
+		 * branches &c small.
+		 */
+		mlen -= 1;
+		while ((mlen -= 32) >= 0) {
+			/*
+			 * Add with carry 16 words and fold in the last
+			 * carry by adding a 0 with carry.
+			 *
+			 * The early ADD(16) and the LOAD(32) are to load
+			 * the next 2 cache lines in advance on 486's.  The
+			 * 486 has a penalty of 2 clock cycles for loading
+			 * a cache line, plus whatever time the external
+			 * memory takes to load the first word(s) addressed.
+			 * These penalties are unavoidable.  Subsequent
+			 * accesses to a cache line being loaded (and to
+			 * other external memory?) are delayed until the
+			 * whole load finishes.  These penalties are mostly
+			 * avoided by not accessing external memory for
+			 * 8 cycles after the ADD(16) and 12 cycles after
+			 * the LOAD(32).  The loop terminates when mlen
+			 * is initially 33 (not 32) to guaranteed that
+			 * the LOAD(32) is within bounds.
+			 */
+			__asm __volatile (
+				"addl %1, %0\n"
+				"adcl %2, %0\n"
+				"adcl %3, %0\n"
+				"adcl %4, %0\n"
+				"adcl %5, %0\n"
+				"mov  %6, %%eax\n"
+				"adcl %7, %0\n"
+				"adcl %8, %0\n"
+				"adcl %9, %0\n"
+				"adcl $0, %0"
+				: "+r" (sum)
+				: "g" (((const u_int32_t *)w)[4]),
+				  "g" (((const u_int32_t *)w)[0]),
+				  "g" (((const u_int32_t *)w)[1]),
+				  "g" (((const u_int32_t *)w)[2]),
+				  "g" (((const u_int32_t *)w)[3]),
+				  "g" (((const u_int32_t *)w)[8]),
+				  "g" (((const u_int32_t *)w)[5]),
+				  "g" (((const u_int32_t *)w)[6]),
+				  "g" (((const u_int32_t *)w)[7])
+				: "eax"
+			);
+			w += 16;
+		}
+		mlen += 32 + 1;
+		if (mlen >= 32) {
+			__asm __volatile (
+				"addl %1, %0\n"
+				"adcl %2, %0\n"
+				"adcl %3, %0\n"
+				"adcl %4, %0\n"
+				"adcl %5, %0\n"
+				"adcl %6, %0\n"
+				"adcl %7, %0\n"
+				"adcl %8, %0\n"
+				"adcl $0, %0"
+				: "+r" (sum)
+				: "g" (((const u_int32_t *)w)[4]),
+				  "g" (((const u_int32_t *)w)[0]),
+				  "g" (((const u_int32_t *)w)[1]),
+				  "g" (((const u_int32_t *)w)[2]),
+				  "g" (((const u_int32_t *)w)[3]),
+				  "g" (((const u_int32_t *)w)[5]),
+				  "g" (((const u_int32_t *)w)[6]),
+				  "g" (((const u_int32_t *)w)[7])
+			);
+			w += 16;
+			mlen -= 32;
+		}
+		if (mlen >= 16) {
+			__asm __volatile (
+				"addl %1, %0\n"
+				"adcl %2, %0\n"
+				"adcl %3, %0\n"
+				"adcl %4, %0\n"
+				"adcl $0, %0"
+				: "+r" (sum)
+				: "g" (((const u_int32_t *)w)[0]),
+				  "g" (((const u_int32_t *)w)[1]),
+				  "g" (((const u_int32_t *)w)[2]),
+				  "g" (((const u_int32_t *)w)[3])
+			);
+			w += 8;
+			mlen -= 16;
+		}
+		if (mlen >= 8) {
+			__asm __volatile (
+				"addl %1, %0\n"
+				"adcl %2, %0\n"
+				"adcl $0, %0"
+				: "+r" (sum)
+				: "g" (((const u_int32_t *)w)[0]),
+				  "g" (((const u_int32_t *)w)[1])
+			);
+			w += 4;
+			mlen -= 8;
+		}
+		if (mlen == 0 && byte_swapped == 0)
+			continue;       /* worth 1% maybe ?? */
+		REDUCE;
+		while ((mlen -= 2) >= 0) {
+			sum += *w++;
+		}
+		if (byte_swapped) {
+			sum <<= 8;
+			byte_swapped = 0;
+			if (mlen == -1) {
+				su.c[1] = *(char *)w;
+				sum += su.s;
+				mlen = 0;
+			} else
+				mlen = -1;
+		} else if (mlen == -1)
+			/*
+			 * This mbuf has odd number of bytes.
+			 * There could be a word split betwen
+			 * this mbuf and the next mbuf.
+			 * Save the last byte (to prepend to next mbuf).
+			 */
+			su.c[0] = *(char *)w;
+	}
+
+	if (len)
+		printf("%s: out of data by %d\n", __func__, len);
+	if (mlen == -1) {
+		/* The last mbuf has odd # of bytes. Follow the
+		   standard (the odd byte is shifted left by 8 bits) */
+		su.c[1] = 0;
+		sum += su.s;
+	}
+	REDUCE;
+	return (~sum & 0xffff);
+}
+#endif
Index: trunk/src/VBox/Devices/Network/slirp/bsd/i386/include/in_cksum.h
===================================================================
--- trunk/src/VBox/Devices/Network/slirp/bsd/i386/include/in_cksum.h	(revision 27869)
+++ trunk/src/VBox/Devices/Network/slirp/bsd/i386/include/in_cksum.h	(revision 27869)
@@ -0,0 +1,145 @@
+/*-
+ * Copyright (c) 1990 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
+ *    documentation and/or other materials provided with the distribution.
+ * 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.
+ *
+ *	from tahoe:	in_cksum.c	1.2	86/01/05
+ *	from:		@(#)in_cksum.c	1.3 (Berkeley) 1/19/91
+ *	from: Id: in_cksum.c,v 1.8 1995/12/03 18:35:19 bde Exp
+ * $FreeBSD: src/sys/i386/include/in_cksum.h,v 1.17.10.1.6.1 2009/04/15 03:14:26 kensmith Exp $
+ */
+
+#ifndef _MACHINE_IN_CKSUM_H_
+#define	_MACHINE_IN_CKSUM_H_	1
+
+#ifndef VBOX
+#ifndef _SYS_CDEFS_H_
+#error this file needs sys/cdefs.h as a prerequisite
+#endif
+
+/*
+ * MP safe (alfred)
+ */
+
+#include <sys/cdefs.h>
+#else
+# include "slirp.h"
+#endif
+
+#define in_cksum(m, len)	in_cksum_skip(m, len, 0)
+
+/*
+ * It it useful to have an Internet checksum routine which is inlineable
+ * and optimized specifically for the task of computing IP header checksums
+ * in the normal case (where there are no options and the header length is
+ * therefore always exactly five 32-bit words.
+ */
+#if defined(__GNUCLIKE_ASM) && !defined(__INTEL_COMPILER)
+static __inline u_int
+in_cksum_hdr(const struct ip *ip)
+{
+	register u_int sum = 0;
+
+	__asm __volatile (
+		"addl %1, %0\n"
+		"adcl %2, %0\n"
+		"adcl %3, %0\n"
+		"adcl %4, %0\n"
+		"adcl %5, %0\n"
+		"adcl $0, %0"
+		: "+r" (sum)
+		: "g" (((const u_int32_t *)ip)[0]),
+		  "g" (((const u_int32_t *)ip)[1]),
+		  "g" (((const u_int32_t *)ip)[2]),
+		  "g" (((const u_int32_t *)ip)[3]),
+		  "g" (((const u_int32_t *)ip)[4])
+	);
+	sum = (sum & 0xffff) + (sum >> 16);
+	if (sum > 0xffff)
+		sum -= 0xffff;
+
+	return ~sum & 0xffff;
+}
+
+static __inline void
+in_cksum_update(struct ip *ip)
+{
+	int __tmpsum;
+	__tmpsum = (int)ntohs(ip->ip_sum) + 256;
+	ip->ip_sum = htons(__tmpsum + (__tmpsum >> 16));
+}
+
+static __inline u_short
+in_addword(u_short sum, u_short b)
+{
+	/* __volatile is necessary because the condition codes are used. */
+	__asm __volatile (
+		"addw %1, %0\n"
+		"adcw $0, %0"
+		: "+r" (sum)
+		: "r" (b)
+	);
+	return (sum);
+}
+
+static __inline u_short
+in_pseudo(u_int sum, u_int b, u_int c)
+{
+	/* __volatile is necessary because the condition codes are used. */
+	__asm __volatile (
+		"addl %1, %0\n"
+		"adcl %2, %0\n"
+		"adcl $0, %0"
+		: "+r" (sum)
+		: "g" (b),
+		  "g" (c)
+	);
+	sum = (sum & 0xffff) + (sum >> 16);
+	if (sum > 0xffff)
+		sum -= 0xffff;
+	return (sum);
+}
+
+#else
+#define	in_cksum_update(ip) \
+	do { \
+		int __tmpsum; \
+		__tmpsum = (int)ntohs(ip->ip_sum) + 256; \
+		ip->ip_sum = htons(__tmpsum + (__tmpsum >> 16)); \
+	} while(0)
+
+#endif
+
+#if defined(_KERNEL) || defined(VBOX)
+#if !defined(__GNUCLIKE_ASM) || defined(__INTEL_COMPILER)
+u_int in_cksum_hdr(const struct ip *ip);
+u_short in_addword(u_short sum, u_short b);
+u_short in_pseudo(u_int sum, u_int b, u_int c);
+#endif
+u_short in_cksum_skip(struct mbuf *m, int len, int skip);
+#endif /* _KERNEL */
+
+#endif /* _MACHINE_IN_CKSUM_H_ */
Index: trunk/src/VBox/Devices/Network/slirp/bsd/kern/kern_mbuf.c
===================================================================
--- trunk/src/VBox/Devices/Network/slirp/bsd/kern/kern_mbuf.c	(revision 27869)
+++ trunk/src/VBox/Devices/Network/slirp/bsd/kern/kern_mbuf.c	(revision 27869)
@@ -0,0 +1,789 @@
+/*-
+ * Copyright (c) 2004, 2005,
+ * 	Bosko Milekic <bmilekic@FreeBSD.org>.  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 unmodified, 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+ */
+
+#ifndef VBOX
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/kern/kern_mbuf.c,v 1.32.2.5.2.1 2009/04/15 03:14:26 kensmith Exp $");
+
+#include "opt_mac.h"
+#include "opt_param.h"
+
+#include <sys/param.h>
+#include <sys/malloc.h>
+#include <sys/systm.h>
+#include <sys/mbuf.h>
+#include <sys/domain.h>
+#include <sys/eventhandler.h>
+#include <sys/kernel.h>
+#include <sys/protosw.h>
+#include <sys/smp.h>
+#include <sys/sysctl.h>
+
+#include <security/mac/mac_framework.h>
+
+#include <vm/vm.h>
+#include <vm/vm_page.h>
+#include <vm/uma.h>
+#include <vm/uma_int.h>
+#include <vm/uma_dbg.h>
+#else
+# include <iprt/param.h>
+# include <slirp.h>
+# define IN_BSD
+# include "ext.h"
+#endif
+
+/*
+ * In FreeBSD, Mbufs and Mbuf Clusters are allocated from UMA
+ * Zones.
+ *
+ * Mbuf Clusters (2K, contiguous) are allocated from the Cluster
+ * Zone.  The Zone can be capped at kern.ipc.nmbclusters, if the
+ * administrator so desires.
+ *
+ * Mbufs are allocated from a UMA Master Zone called the Mbuf
+ * Zone.
+ *
+ * Additionally, FreeBSD provides a Packet Zone, which it
+ * configures as a Secondary Zone to the Mbuf Master Zone,
+ * thus sharing backend Slab kegs with the Mbuf Master Zone.
+ *
+ * Thus common-case allocations and locking are simplified:
+ *
+ *  m_clget()                m_getcl()
+ *    |                         |
+ *    |   .------------>[(Packet Cache)]    m_get(), m_gethdr()
+ *    |   |             [     Packet   ]            |
+ *  [(Cluster Cache)]   [    Secondary ]   [ (Mbuf Cache)     ]
+ *  [ Cluster Zone  ]   [     Zone     ]   [ Mbuf Master Zone ]
+ *        |                       \________         |
+ *  [ Cluster Keg   ]                      \       /
+ *        |    	                         [ Mbuf Keg   ]
+ *  [ Cluster Slabs ]                         |
+ *        |                              [ Mbuf Slabs ]
+ *         \____________(VM)_________________/
+ *
+ *
+ * Whenever an object is allocated with uma_zalloc() out of
+ * one of the Zones its _ctor_ function is executed.  The same
+ * for any deallocation through uma_zfree() the _dtor_ function
+ * is executed.
+ *
+ * Caches are per-CPU and are filled from the Master Zone.
+ *
+ * Whenever an object is allocated from the underlying global
+ * memory pool it gets pre-initialized with the _zinit_ functions.
+ * When the Keg's are overfull objects get decomissioned with
+ * _zfini_ functions and free'd back to the global memory pool.
+ *
+ */
+
+#ifndef VBOX
+int nmbclusters;		/* limits number of mbuf clusters */
+int nmbjumbop;			/* limits number of page size jumbo clusters */
+int nmbjumbo9;			/* limits number of 9k jumbo clusters */
+int nmbjumbo16;			/* limits number of 16k jumbo clusters */
+struct mbstat mbstat;
+#endif
+
+/*
+ * tunable_mbinit() has to be run before init_maxsockets() thus
+ * the SYSINIT order below is SI_ORDER_MIDDLE while init_maxsockets()
+ * runs at SI_ORDER_ANY.
+ */
+static void
+tunable_mbinit(void *dummy)
+{
+#ifdef VBOX
+        PNATState pData = (PNATState)dummy;
+#endif
+	/* This has to be done before VM init. */
+	nmbclusters = 1024 + maxusers * 64;
+	nmbjumbop = nmbclusters / 2;
+	nmbjumbo9 = nmbjumbop / 2;
+	nmbjumbo16 = nmbjumbo9 / 2;
+	TUNABLE_INT_FETCH("kern.ipc.nmbclusters", &nmbclusters);
+}
+SYSINIT(tunable_mbinit, SI_SUB_TUNABLES, SI_ORDER_MIDDLE, tunable_mbinit, NULL);
+
+/* XXX: These should be tuneables. Can't change UMA limits on the fly. */
+static int
+sysctl_nmbclusters(SYSCTL_HANDLER_ARGS)
+{
+	int error, newnmbclusters;
+
+	newnmbclusters = nmbclusters;
+	error = sysctl_handle_int(oidp, &newnmbclusters, 0, req);
+	if (error == 0 && req->newptr) {
+		if (newnmbclusters > nmbclusters) {
+			nmbclusters = newnmbclusters;
+			uma_zone_set_max(zone_clust, nmbclusters);
+			EVENTHANDLER_INVOKE(nmbclusters_change);
+		} else
+			error = EINVAL;
+	}
+	return (error);
+}
+SYSCTL_PROC(_kern_ipc, OID_AUTO, nmbclusters, CTLTYPE_INT|CTLFLAG_RW,
+&nmbclusters, 0, sysctl_nmbclusters, "IU",
+    "Maximum number of mbuf clusters allowed");
+
+static int
+sysctl_nmbjumbop(SYSCTL_HANDLER_ARGS)
+{
+	int error, newnmbjumbop;
+
+	newnmbjumbop = nmbjumbop;
+	error = sysctl_handle_int(oidp, &newnmbjumbop, 0, req);
+	if (error == 0 && req->newptr) {
+		if (newnmbjumbop> nmbjumbop) {
+			nmbjumbop = newnmbjumbop;
+			uma_zone_set_max(zone_jumbop, nmbjumbop);
+		} else
+			error = EINVAL;
+	}
+	return (error);
+}
+SYSCTL_PROC(_kern_ipc, OID_AUTO, nmbjumbop, CTLTYPE_INT|CTLFLAG_RW,
+&nmbjumbop, 0, sysctl_nmbjumbop, "IU",
+	 "Maximum number of mbuf page size jumbo clusters allowed");
+
+
+static int
+sysctl_nmbjumbo9(SYSCTL_HANDLER_ARGS)
+{
+	int error, newnmbjumbo9;
+
+	newnmbjumbo9 = nmbjumbo9;
+	error = sysctl_handle_int(oidp, &newnmbjumbo9, 0, req);
+	if (error == 0 && req->newptr) {
+		if (newnmbjumbo9> nmbjumbo9) {
+			nmbjumbo9 = newnmbjumbo9;
+			uma_zone_set_max(zone_jumbo9, nmbjumbo9);
+		} else
+			error = EINVAL;
+	}
+	return (error);
+}
+SYSCTL_PROC(_kern_ipc, OID_AUTO, nmbjumbo9, CTLTYPE_INT|CTLFLAG_RW,
+&nmbjumbo9, 0, sysctl_nmbjumbo9, "IU",
+	"Maximum number of mbuf 9k jumbo clusters allowed");
+
+static int
+sysctl_nmbjumbo16(SYSCTL_HANDLER_ARGS)
+{
+	int error, newnmbjumbo16;
+
+	newnmbjumbo16 = nmbjumbo16;
+	error = sysctl_handle_int(oidp, &newnmbjumbo16, 0, req);
+	if (error == 0 && req->newptr) {
+		if (newnmbjumbo16> nmbjumbo16) {
+			nmbjumbo16 = newnmbjumbo16;
+			uma_zone_set_max(zone_jumbo16, nmbjumbo16);
+		} else
+			error = EINVAL;
+	}
+	return (error);
+}
+SYSCTL_PROC(_kern_ipc, OID_AUTO, nmbjumbo16, CTLTYPE_INT|CTLFLAG_RW,
+&nmbjumbo16, 0, sysctl_nmbjumbo16, "IU",
+    "Maximum number of mbuf 16k jumbo clusters allowed");
+
+
+
+SYSCTL_STRUCT(_kern_ipc, OID_AUTO, mbstat, CTLFLAG_RD, &mbstat, mbstat,
+    "Mbuf general information and statistics");
+
+/*
+ * Zones from which we allocate.
+ */
+#ifndef VBOX
+uma_zone_t	zone_mbuf;
+uma_zone_t	zone_clust;
+uma_zone_t	zone_pack;
+uma_zone_t	zone_jumbop;
+uma_zone_t	zone_jumbo9;
+uma_zone_t	zone_jumbo16;
+uma_zone_t	zone_ext_refcnt;
+
+/*
+ * Local prototypes.
+ */
+static int	mb_ctor_mbuf(void *, int, void *, int);
+static int	mb_ctor_clust(void *, int, void *, int);
+static int	mb_ctor_pack(void *, int, void *, int);
+static void	mb_dtor_mbuf(void *, int, void *);
+static void	mb_dtor_clust(void *, int, void *);
+static void	mb_dtor_pack(void *, int, void *);
+static int	mb_zinit_pack(void *, int, int);
+static void	mb_zfini_pack(void *, int);
+#else
+/*
+ * Local prototypes.
+ */
+static int	mb_ctor_mbuf(PNATState, void *, int, void *, int);
+static int	mb_ctor_clust(PNATState, void *, int, void *, int);
+static int	mb_ctor_pack(PNATState, void *, int, void *, int);
+static void	mb_dtor_mbuf(PNATState, void *, int, void *);
+static void	mb_dtor_clust(PNATState, void *, int, void *);
+static void	mb_dtor_pack(PNATState, void *, int, void *);
+static int	mb_zinit_pack(PNATState, void *, int, int);
+static void	mb_zfini_pack(PNATState, void *, int);
+#endif
+
+static void	mb_reclaim(void *);
+#ifndef VBOX
+static void	mbuf_init(void *);
+#endif
+static void    *mbuf_jumbo_alloc(uma_zone_t, int, u_int8_t *, int);
+static void	mbuf_jumbo_free(void *, int, u_int8_t);
+
+#ifndef VBOX
+static MALLOC_DEFINE(M_JUMBOFRAME, "jumboframes", "mbuf jumbo frame buffers");
+
+/* Ensure that MSIZE doesn't break dtom() - it must be a power of 2 */
+CTASSERT((((MSIZE - 1) ^ MSIZE) + 1) >> 1 == MSIZE);
+#else
+#define uma_zcreate(a0, a1, a2, a3, a4, a5, a6, a7) \
+    uma_zcreate(pData, a0, a1, a2, a3, a4, a5, a6, a7)
+#endif
+
+/*
+ * Initialize FreeBSD Network buffer allocation.
+ */
+SYSINIT(mbuf, SI_SUB_MBUF, SI_ORDER_FIRST, mbuf_init, NULL);
+#ifndef VBOX
+static void
+#else
+void
+#endif
+mbuf_init(void *dummy)
+{
+
+	/*
+	 * Configure UMA zones for Mbufs, Clusters, and Packets.
+	 */
+#ifndef VBOX
+	zone_mbuf = uma_zcreate(MBUF_MEM_NAME, MSIZE,
+	    mb_ctor_mbuf, mb_dtor_mbuf,
+#ifdef INVARIANTS
+	    trash_init, trash_fini,
+#else
+	    NULL, NULL,
+#endif
+	    MSIZE - 1, UMA_ZONE_MAXBUCKET);
+
+	zone_clust = uma_zcreate(MBUF_CLUSTER_MEM_NAME, MCLBYTES,
+	    mb_ctor_clust, mb_dtor_clust,
+#ifdef INVARIANTS
+	    trash_init, trash_fini,
+#else
+	    NULL, NULL,
+#endif
+	    UMA_ALIGN_PTR, UMA_ZONE_REFCNT);
+#else /*!VBOX*/
+        PNATState pData = (PNATState)dummy;
+        tunable_mbinit(pData);
+	zone_mbuf = uma_zcreate(MBUF_MEM_NAME, MSIZE,
+	    mb_ctor_mbuf, mb_dtor_mbuf,
+	    NULL, NULL,
+	    MSIZE - 1, UMA_ZONE_MAXBUCKET);
+
+	zone_clust = uma_zcreate(MBUF_CLUSTER_MEM_NAME, MCLBYTES,
+	    mb_ctor_clust, mb_dtor_clust,
+	    NULL, NULL,
+	    UMA_ALIGN_PTR, UMA_ZONE_REFCNT);
+#endif /*VBOX*/
+	if (nmbclusters > 0)
+		uma_zone_set_max(zone_clust, nmbclusters);
+
+	zone_pack = uma_zsecond_create(MBUF_PACKET_MEM_NAME, mb_ctor_pack,
+	    mb_dtor_pack, mb_zinit_pack, mb_zfini_pack, zone_mbuf);
+
+	/* Make jumbo frame zone too. Page size, 9k and 16k. */
+#ifndef VBOX
+	zone_jumbop = uma_zcreate(MBUF_JUMBOP_MEM_NAME, MJUMPAGESIZE,
+	    mb_ctor_clust, mb_dtor_clust,
+#ifdef INVARIANTS
+	    trash_init, trash_fini,
+#else
+	    NULL, NULL,
+#endif
+	    UMA_ALIGN_PTR, UMA_ZONE_REFCNT);
+	if (nmbjumbop > 0)
+		uma_zone_set_max(zone_jumbop, nmbjumbop);
+
+	zone_jumbo9 = uma_zcreate(MBUF_JUMBO9_MEM_NAME, MJUM9BYTES,
+	    mb_ctor_clust, mb_dtor_clust,
+#ifdef INVARIANTS
+	    trash_init, trash_fini,
+#else
+	    NULL, NULL,
+#endif
+	    UMA_ALIGN_PTR, UMA_ZONE_REFCNT);
+	if (nmbjumbo9 > 0)
+		uma_zone_set_max(zone_jumbo9, nmbjumbo9);
+	uma_zone_set_allocf(zone_jumbo9, mbuf_jumbo_alloc);
+	uma_zone_set_freef(zone_jumbo9, mbuf_jumbo_free);
+
+	zone_jumbo16 = uma_zcreate(MBUF_JUMBO16_MEM_NAME, MJUM16BYTES,
+	    mb_ctor_clust, mb_dtor_clust,
+#ifdef INVARIANTS
+	    trash_init, trash_fini,
+#else
+	    NULL, NULL,
+#endif
+	    UMA_ALIGN_PTR, UMA_ZONE_REFCNT);
+	if (nmbjumbo16 > 0)
+		uma_zone_set_max(zone_jumbo16, nmbjumbo16);
+#else /*!VBOX*/
+	zone_jumbop = uma_zcreate(MBUF_JUMBOP_MEM_NAME, MJUMPAGESIZE,
+	    mb_ctor_clust, mb_dtor_clust,
+	    NULL, NULL,
+	    UMA_ALIGN_PTR, UMA_ZONE_REFCNT);
+	if (nmbjumbop > 0)
+		uma_zone_set_max(zone_jumbop, nmbjumbop);
+
+	zone_jumbo9 = uma_zcreate(MBUF_JUMBO9_MEM_NAME, MJUM9BYTES,
+	    mb_ctor_clust, mb_dtor_clust,
+	    NULL, NULL,
+	    UMA_ALIGN_PTR, UMA_ZONE_REFCNT);
+	if (nmbjumbo9 > 0)
+		uma_zone_set_max(zone_jumbo9, nmbjumbo9);
+
+	zone_jumbo16 = uma_zcreate(MBUF_JUMBO16_MEM_NAME, MJUM16BYTES,
+	    mb_ctor_clust, mb_dtor_clust,
+	    NULL, NULL,
+	    UMA_ALIGN_PTR, UMA_ZONE_REFCNT);
+	if (nmbjumbo16 > 0)
+		uma_zone_set_max(zone_jumbo16, nmbjumbo16);
+#endif /*VBOX*/
+
+	zone_ext_refcnt = uma_zcreate(MBUF_EXTREFCNT_MEM_NAME, sizeof(u_int),
+	    NULL, NULL,
+	    NULL, NULL,
+	    UMA_ALIGN_PTR, UMA_ZONE_ZINIT);
+
+	/* uma_prealloc() goes here... */
+
+	/*
+	 * Hook event handler for low-memory situation, used to
+	 * drain protocols and push data back to the caches (UMA
+	 * later pushes it back to VM).
+	 */
+	EVENTHANDLER_REGISTER(vm_lowmem, mb_reclaim, NULL,
+	    EVENTHANDLER_PRI_FIRST);
+
+	/*
+	 * [Re]set counters and local statistics knobs.
+	 * XXX Some of these should go and be replaced, but UMA stat
+	 * gathering needs to be revised.
+	 */
+	mbstat.m_mbufs = 0;
+	mbstat.m_mclusts = 0;
+	mbstat.m_drain = 0;
+	mbstat.m_msize = MSIZE;
+	mbstat.m_mclbytes = MCLBYTES;
+	mbstat.m_minclsize = MINCLSIZE;
+	mbstat.m_mlen = MLEN;
+	mbstat.m_mhlen = MHLEN;
+	mbstat.m_numtypes = MT_NTYPES;
+
+	mbstat.m_mcfail = mbstat.m_mpfail = 0;
+	mbstat.sf_iocnt = 0;
+	mbstat.sf_allocwait = mbstat.sf_allocfail = 0;
+}
+
+/*
+ * UMA backend page allocator for the jumbo frame zones.
+ *
+ * Allocates kernel virtual memory that is backed by contiguous physical
+ * pages.
+ */
+static void *
+mbuf_jumbo_alloc(uma_zone_t zone, int bytes, u_int8_t *flags, int wait)
+{
+
+#ifndef VBOX
+	/* Inform UMA that this allocator uses kernel_map/object. */
+	*flags = UMA_SLAB_KERNEL;
+	return (contigmalloc(bytes, M_JUMBOFRAME, wait, (vm_paddr_t)0,
+	    ~(vm_paddr_t)0, 1, 0));
+#else
+        return RTMemAlloc(bytes);
+#endif
+}
+
+/*
+ * UMA backend page deallocator for the jumbo frame zones.
+ */
+static void
+mbuf_jumbo_free(void *mem, int size, u_int8_t flags)
+{
+
+#ifndef VBOX
+	contigfree(mem, size, M_JUMBOFRAME);
+#else
+        RTMemFree(mem);
+#endif
+}
+
+/*
+ * Constructor for Mbuf master zone.
+ *
+ * The 'arg' pointer points to a mb_args structure which
+ * contains call-specific information required to support the
+ * mbuf allocation API.  See mbuf.h.
+ */
+static int
+#ifndef VBOX
+mb_ctor_mbuf(void *mem, int size, void *arg, int how)
+#else
+mb_ctor_mbuf(PNATState pData, void *mem, int size, void *arg, int how)
+#endif
+{
+	struct mbuf *m;
+	struct mb_args *args;
+#ifdef MAC
+	int error;
+#endif
+	int flags;
+	short type;
+
+#ifdef INVARIANTS
+	trash_ctor(mem, size, arg, how);
+#endif
+	m = (struct mbuf *)mem;
+	args = (struct mb_args *)arg;
+	flags = args->flags;
+	type = args->type;
+
+	/*
+	 * The mbuf is initialized later.  The caller has the
+	 * responsibility to set up any MAC labels too.
+	 */
+	if (type == MT_NOINIT)
+		return (0);
+
+	m->m_next = NULL;
+	m->m_nextpkt = NULL;
+	m->m_len = 0;
+	m->m_flags = flags;
+	m->m_type = type;
+	if (flags & M_PKTHDR) {
+		m->m_data = m->m_pktdat;
+		m->m_pkthdr.rcvif = NULL;
+		m->m_pkthdr.len = 0;
+		m->m_pkthdr.header = NULL;
+		m->m_pkthdr.csum_flags = 0;
+		m->m_pkthdr.csum_data = 0;
+		m->m_pkthdr.tso_segsz = 0;
+		m->m_pkthdr.ether_vtag = 0;
+		SLIST_INIT(&m->m_pkthdr.tags);
+#ifdef MAC
+		/* If the label init fails, fail the alloc */
+		error = mac_init_mbuf(m, how);
+		if (error)
+			return (error);
+#endif
+	} else
+		m->m_data = m->m_dat;
+	return (0);
+}
+
+/*
+ * The Mbuf master zone destructor.
+ */
+static void
+#ifndef VBOX
+mb_dtor_mbuf(void *mem, int size, void *arg)
+#else
+mb_dtor_mbuf(PNATState pData, void *mem, int size, void *arg)
+#endif
+{
+	struct mbuf *m;
+	unsigned long flags;
+
+	m = (struct mbuf *)mem;
+	flags = (unsigned long)arg;
+
+	if ((flags & MB_NOTAGS) == 0 && (m->m_flags & M_PKTHDR) != 0)
+		m_tag_delete_chain(m, NULL);
+	KASSERT((m->m_flags & M_EXT) == 0, ("%s: M_EXT set", __func__));
+	KASSERT((m->m_flags & M_NOFREE) == 0, ("%s: M_NOFREE set", __func__));
+#ifdef INVARIANTS
+	trash_dtor(mem, size, arg);
+#endif
+}
+
+/*
+ * The Mbuf Packet zone destructor.
+ */
+static void
+#ifndef VBOX
+mb_dtor_pack(void *mem, int size, void *arg)
+#else
+mb_dtor_pack(PNATState pData, void *mem, int size, void *arg)
+#endif
+{
+	struct mbuf *m;
+
+	m = (struct mbuf *)mem;
+	if ((m->m_flags & M_PKTHDR) != 0)
+		m_tag_delete_chain(m, NULL);
+
+	/* Make sure we've got a clean cluster back. */
+	KASSERT((m->m_flags & M_EXT) == M_EXT, ("%s: M_EXT not set", __func__));
+	KASSERT(m->m_ext.ext_buf != NULL, ("%s: ext_buf == NULL", __func__));
+	KASSERT(m->m_ext.ext_free == NULL, ("%s: ext_free != NULL", __func__));
+	KASSERT(m->m_ext.ext_args == NULL, ("%s: ext_args != NULL", __func__));
+	KASSERT(m->m_ext.ext_size == MCLBYTES, ("%s: ext_size != MCLBYTES", __func__));
+	KASSERT(m->m_ext.ext_type == EXT_PACKET, ("%s: ext_type != EXT_PACKET", __func__));
+	KASSERT(*m->m_ext.ref_cnt == 1, ("%s: ref_cnt != 1", __func__));
+#ifdef INVARIANTS
+	trash_dtor(m->m_ext.ext_buf, MCLBYTES, arg);
+#endif
+	/*
+	 * If there are processes blocked on zone_clust, waiting for pages to be freed up,
+	 * cause them to be woken up by draining the packet zone. We are exposed to a race here
+	 * (in the check for the UMA_ZFLAG_FULL) where we might miss the flag set, but that is
+	 * deliberate. We don't want to acquire the zone lock for every mbuf free.
+	 */
+ 	if (uma_zone_exhausted_nolock(zone_clust))
+ 		zone_drain(zone_pack);
+}
+
+/*
+ * The Cluster and Jumbo[PAGESIZE|9|16] zone constructor.
+ *
+ * Here the 'arg' pointer points to the Mbuf which we
+ * are configuring cluster storage for.  If 'arg' is
+ * empty we allocate just the cluster without setting
+ * the mbuf to it.  See mbuf.h.
+ */
+static int
+#ifndef VBOX
+mb_ctor_clust(void *mem, int size, void *arg, int how)
+#else
+mb_ctor_clust(PNATState pData, void *mem, int size, void *arg, int how)
+#endif
+{
+	struct mbuf *m;
+	u_int *refcnt;
+	int type;
+	uma_zone_t zone;
+
+#ifdef INVARIANTS
+	trash_ctor(mem, size, arg, how);
+#endif
+	switch (size) {
+	case MCLBYTES:
+		type = EXT_CLUSTER;
+		zone = zone_clust;
+		break;
+#if MJUMPAGESIZE != MCLBYTES
+	case MJUMPAGESIZE:
+		type = EXT_JUMBOP;
+		zone = zone_jumbop;
+		break;
+#endif
+	case MJUM9BYTES:
+		type = EXT_JUMBO9;
+		zone = zone_jumbo9;
+		break;
+	case MJUM16BYTES:
+		type = EXT_JUMBO16;
+		zone = zone_jumbo16;
+		break;
+	default:
+		panic("unknown cluster size");
+		break;
+	}
+
+	m = (struct mbuf *)arg;
+	refcnt = uma_find_refcnt(zone, mem);
+	*refcnt = 1;
+	if (m != NULL) {
+		m->m_ext.ext_buf = (caddr_t)mem;
+		m->m_data = m->m_ext.ext_buf;
+		m->m_flags |= M_EXT;
+		m->m_ext.ext_free = NULL;
+		m->m_ext.ext_args = NULL;
+		m->m_ext.ext_size = size;
+		m->m_ext.ext_type = type;
+		m->m_ext.ref_cnt = refcnt;
+	}
+
+	return (0);
+}
+
+/*
+ * The Mbuf Cluster zone destructor.
+ */
+static void
+#ifndef VBOX
+mb_dtor_clust(void *mem, int size, void *arg)
+#else
+mb_dtor_clust(PNATState pData, void *mem, int size, void *arg)
+#endif
+{
+#ifdef INVARIANTS
+	uma_zone_t zone;
+
+	zone = m_getzone(size);
+	KASSERT(*(uma_find_refcnt(zone, mem)) <= 1,
+		("%s: refcnt incorrect %u", __func__,
+		 *(uma_find_refcnt(zone, mem))) );
+
+	trash_dtor(mem, size, arg);
+#endif
+}
+
+/*
+ * The Packet secondary zone's init routine, executed on the
+ * object's transition from mbuf keg slab to zone cache.
+ */
+static int
+#ifndef VBOX
+mb_zinit_pack(void *mem, int size, int how)
+#else
+mb_zinit_pack(PNATState pData, void *mem, int size, int how)
+#endif
+{
+	struct mbuf *m;
+
+	m = (struct mbuf *)mem;		/* m is virgin. */
+	if (uma_zalloc_arg(zone_clust, m, how) == NULL ||
+	    m->m_ext.ext_buf == NULL)
+		return (ENOMEM);
+	m->m_ext.ext_type = EXT_PACKET;	/* Override. */
+#ifdef INVARIANTS
+	trash_init(m->m_ext.ext_buf, MCLBYTES, how);
+#endif
+	return (0);
+}
+
+/*
+ * The Packet secondary zone's fini routine, executed on the
+ * object's transition from zone cache to keg slab.
+ */
+static void
+#ifndef VBOX
+mb_zfini_pack(void *mem, int size)
+#else
+mb_zfini_pack(PNATState pData, void *mem, int size)
+#endif
+{
+	struct mbuf *m;
+
+	m = (struct mbuf *)mem;
+#ifdef INVARIANTS
+	trash_fini(m->m_ext.ext_buf, MCLBYTES);
+#endif
+	uma_zfree_arg(zone_clust, m->m_ext.ext_buf, NULL);
+#ifdef INVARIANTS
+	trash_dtor(mem, size, NULL);
+#endif
+}
+
+/*
+ * The "packet" keg constructor.
+ */
+static int
+#ifndef VBOX
+mb_ctor_pack(void *mem, int size, void *arg, int how)
+#else
+mb_ctor_pack(PNATState pData, void *mem, int size, void *arg, int how)
+#endif
+{
+	struct mbuf *m;
+	struct mb_args *args;
+#ifdef MAC
+	int error;
+#endif
+	int flags;
+	short type;
+
+	m = (struct mbuf *)mem;
+	args = (struct mb_args *)arg;
+	flags = args->flags;
+	type = args->type;
+
+#ifdef INVARIANTS
+	trash_ctor(m->m_ext.ext_buf, MCLBYTES, arg, how);
+#endif
+	m->m_next = NULL;
+	m->m_nextpkt = NULL;
+	m->m_data = m->m_ext.ext_buf;
+	m->m_len = 0;
+	m->m_flags = (flags | M_EXT);
+	m->m_type = type;
+
+	if (flags & M_PKTHDR) {
+		m->m_pkthdr.rcvif = NULL;
+		m->m_pkthdr.len = 0;
+		m->m_pkthdr.header = NULL;
+		m->m_pkthdr.csum_flags = 0;
+		m->m_pkthdr.csum_data = 0;
+		m->m_pkthdr.tso_segsz = 0;
+		m->m_pkthdr.ether_vtag = 0;
+		SLIST_INIT(&m->m_pkthdr.tags);
+#ifdef MAC
+		/* If the label init fails, fail the alloc */
+		error = mac_init_mbuf(m, how);
+		if (error)
+			return (error);
+#endif
+	}
+	/* m_ext is already initialized. */
+
+	return (0);
+}
+
+/*
+ * This is the protocol drain routine.
+ *
+ * No locks should be held when this is called.  The drain routines have to
+ * presently acquire some locks which raises the possibility of lock order
+ * reversal.
+ */
+static void
+mb_reclaim(void *junk)
+{
+#ifndef VBOX
+	struct domain *dp;
+	struct protosw *pr;
+
+	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK | WARN_PANIC, NULL,
+	    "mb_reclaim()");
+
+	for (dp = domains; dp != NULL; dp = dp->dom_next)
+		for (pr = dp->dom_protosw; pr < dp->dom_protoswNPROTOSW; pr++)
+			if (pr->pr_drain != NULL)
+				(*pr->pr_drain)();
+#endif
+}
Index: trunk/src/VBox/Devices/Network/slirp/bsd/kern/uipc_mbuf.c
===================================================================
--- trunk/src/VBox/Devices/Network/slirp/bsd/kern/uipc_mbuf.c	(revision 27869)
+++ trunk/src/VBox/Devices/Network/slirp/bsd/kern/uipc_mbuf.c	(revision 27869)
@@ -0,0 +1,2232 @@
+/*-
+ * 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
+ *    documentation and/or other materials provided with the distribution.
+ * 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
+#include <sys/cdefs.h>
+__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"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/limits.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/sysctl.h>
+#include <sys/domain.h>
+#include <sys/protosw.h>
+#include <sys/uio.h>
+
+#include <security/mac/mac_framework.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;
+int	m_defragrandomfailures;
+#endif
+
+/*
+ * sysctl(8) exported objects
+ */
+SYSCTL_INT(_kern_ipc, KIPC_MAX_LINKHDR, max_linkhdr, CTLFLAG_RD,
+	   &max_linkhdr, 0, "Size of largest link layer header");
+SYSCTL_INT(_kern_ipc, KIPC_MAX_PROTOHDR, max_protohdr, CTLFLAG_RD,
+	   &max_protohdr, 0, "Size of largest protocol layer header");
+SYSCTL_INT(_kern_ipc, KIPC_MAX_HDR, max_hdr, CTLFLAG_RD,
+	   &max_hdr, 0, "Size of largest link plus protocol header");
+SYSCTL_INT(_kern_ipc, KIPC_MAX_DATALEN, max_datalen, CTLFLAG_RD,
+	   &max_datalen, 0, "Minimum space left in mbuf after max_hdr");
+#ifdef MBUF_STRESS_TEST
+SYSCTL_INT(_kern_ipc, OID_AUTO, m_defragpackets, CTLFLAG_RD,
+	   &m_defragpackets, 0, "");
+SYSCTL_INT(_kern_ipc, OID_AUTO, m_defragbytes, CTLFLAG_RD,
+	   &m_defragbytes, 0, "");
+SYSCTL_INT(_kern_ipc, OID_AUTO, m_defraguseless, CTLFLAG_RD,
+	   &m_defraguseless, 0, "");
+SYSCTL_INT(_kern_ipc, OID_AUTO, m_defragfailure, CTLFLAG_RD,
+	   &m_defragfailure, 0, "");
+SYSCTL_INT(_kern_ipc, OID_AUTO, m_defragrandomfailures, CTLFLAG_RW,
+	   &m_defragrandomfailures, 0, "");
+#endif
+#else /* VBOX */
+# include <iprt/asm.h>
+# include "slirp.h"
+# define atomic_fetchadd_int(var, val) (ASMAtomicAddU32((var), (val)))
+# define __DEVOLATILE(type, var)       ((type)ASMAtomicReadU32((var)))
+# define atomic_add_int(var, val)      (ASMAtomicAddU32((var), (val)))
+#endif /* VBOX */
+
+/*
+ * Allocate a given length worth of mbufs and/or clusters (whatever fits
+ * 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
+m_getm2(struct mbuf *m, int len, int how, short type, int flags)
+#else
+m_getm2(PNATState pData, struct mbuf *m, int len, int how, short type, int flags)
+#endif
+{
+	struct mbuf *mb, *nm = NULL, *mtail = NULL;
+
+	KASSERT(len >= 0, ("%s: len is < 0", __func__));
+
+	/* Validate flags. */
+	flags &= (M_PKTHDR | M_EOR);
+
+	/* Packet header mbuf must be first in chain. */
+	if ((flags & M_PKTHDR) && m != NULL)
+		flags &= ~M_PKTHDR;
+
+	/* Loop and append maximum sized mbufs to the chain tail. */
+	while (len > 0) {
+#ifndef VBOX
+		if (len > MCLBYTES)
+			mb = m_getjcl(how, type, (flags & M_PKTHDR),
+			    MJUMPAGESIZE);
+		else if (len >= MINCLSIZE)
+			mb = m_getcl(how, type, (flags & M_PKTHDR));
+		else if (flags & M_PKTHDR)
+			mb = m_gethdr(how, type);
+		else
+			mb = m_get(how, type);
+
+		/* Fail the whole operation if one mbuf can't be allocated. */
+		if (mb == NULL) {
+			if (nm != NULL)
+				m_freem(nm);
+			return (NULL);
+		}
+#else
+		if (len > MCLBYTES)
+			mb = m_getjcl(pData, how, type, (flags & M_PKTHDR),
+			    MJUMPAGESIZE);
+		else if (len >= MINCLSIZE)
+			mb = m_getcl(pData, how, type, (flags & M_PKTHDR));
+		else if (flags & M_PKTHDR)
+			mb = m_gethdr(pData, how, type);
+		else
+			mb = m_get(pData, how, type);
+		/* Fail the whole operation if one mbuf can't be allocated. */
+		if (mb == NULL) {
+			if (nm != NULL)
+				m_freem(pData, nm);
+			return (NULL);
+		}
+#endif
+
+		/* Book keeping. */
+		len -= (mb->m_flags & M_EXT) ? mb->m_ext.ext_size :
+			((mb->m_flags & M_PKTHDR) ? MHLEN : MLEN);
+		if (mtail != NULL)
+			mtail->m_next = mb;
+		else
+			nm = mb;
+		mtail = mb;
+		flags &= ~M_PKTHDR;	/* Only valid on the first mbuf. */
+	}
+	if (flags & M_EOR)
+		mtail->m_flags |= M_EOR;  /* Only valid on the last mbuf. */
+
+	/* If mbuf was supplied, append new chain to the end of it. */
+	if (m != NULL) {
+		for (mtail = m; mtail->m_next != NULL; mtail = mtail->m_next)
+			;
+		mtail->m_next = nm;
+		mtail->m_flags &= ~M_EOR;
+	} else
+		m = nm;
+
+	return (m);
+}
+
+/*
+ * Free an entire chain of mbufs and associated external buffers, if
+ * applicable.
+ */
+void
+#ifndef VBOX
+m_freem(struct mbuf *mb)
+#else
+m_freem(PNATState pData, struct mbuf *mb)
+#endif
+{
+
+	while (mb != NULL)
+		mb = m_free(pData, mb);
+}
+
+/*-
+ * 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
+m_extadd(struct mbuf *mb, caddr_t buf, u_int size,
+    void (*freef)(void *, void *), void *args, int flags, int type)
+#else
+m_extadd(PNATState pData, struct mbuf *mb, caddr_t buf, u_int size,
+    void (*freef)(void *, void *), void *args, int flags, int type)
+#endif
+{
+	KASSERT(type != EXT_CLUSTER, ("%s: EXT_CLUSTER not allowed", __func__));
+
+	if (type != EXT_EXTREF)
+		mb->m_ext.ref_cnt = (u_int *)uma_zalloc(zone_ext_refcnt, M_NOWAIT);
+	if (mb->m_ext.ref_cnt != NULL) {
+		*(mb->m_ext.ref_cnt) = 1;
+		mb->m_flags |= (M_EXT | flags);
+		mb->m_ext.ext_buf = buf;
+		mb->m_data = mb->m_ext.ext_buf;
+		mb->m_ext.ext_size = size;
+		mb->m_ext.ext_free = freef;
+		mb->m_ext.ext_args = args;
+		mb->m_ext.ext_type = type;
+        }
+}
+
+/*
+ * 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
+mb_free_ext(struct mbuf *m)
+#else
+mb_free_ext(PNATState pData, struct mbuf *m)
+#endif
+{
+	int skipmbuf;
+
+	KASSERT((m->m_flags & M_EXT) == M_EXT, ("%s: M_EXT not set", __func__));
+	KASSERT(m->m_ext.ref_cnt != NULL, ("%s: ref_cnt not set", __func__));
+
+
+	/*
+	 * check if the header is embedded in the cluster
+	 */
+	skipmbuf = (m->m_flags & M_NOFREE);
+
+	/* Free attached storage if this mbuf is the only reference to it. */
+	if (*(m->m_ext.ref_cnt) == 1 ||
+	    atomic_fetchadd_int(m->m_ext.ref_cnt, -1) == 1) {
+		switch (m->m_ext.ext_type) {
+		case EXT_PACKET:	/* The packet zone is special. */
+			if (*(m->m_ext.ref_cnt) == 0)
+				*(m->m_ext.ref_cnt) = 1;
+			uma_zfree(zone_pack, m);
+			return;		/* Job done. */
+		case EXT_CLUSTER:
+			uma_zfree(zone_clust, m->m_ext.ext_buf);
+			break;
+		case EXT_JUMBOP:
+			uma_zfree(zone_jumbop, m->m_ext.ext_buf);
+			break;
+		case EXT_JUMBO9:
+			uma_zfree(zone_jumbo9, m->m_ext.ext_buf);
+			break;
+		case EXT_JUMBO16:
+			uma_zfree(zone_jumbo16, m->m_ext.ext_buf);
+			break;
+		case EXT_SFBUF:
+		case EXT_NET_DRV:
+		case EXT_MOD_TYPE:
+		case EXT_DISPOSABLE:
+			*(m->m_ext.ref_cnt) = 0;
+			uma_zfree(zone_ext_refcnt, __DEVOLATILE(u_int *,
+				m->m_ext.ref_cnt));
+			/* FALLTHROUGH */
+		case EXT_EXTREF:
+			KASSERT(m->m_ext.ext_free != NULL,
+				("%s: ext_free not set", __func__));
+			(*(m->m_ext.ext_free))(m->m_ext.ext_buf,
+			    m->m_ext.ext_args);
+			break;
+		default:
+			KASSERT(m->m_ext.ext_type == 0,
+				("%s: unknown ext_type", __func__));
+		}
+	}
+	if (skipmbuf)
+		return;
+
+	/*
+	 * Free this mbuf back to the mbuf zone with all m_ext
+	 * information purged.
+	 */
+	m->m_ext.ext_buf = NULL;
+	m->m_ext.ext_free = NULL;
+	m->m_ext.ext_args = NULL;
+	m->m_ext.ref_cnt = NULL;
+	m->m_ext.ext_size = 0;
+	m->m_ext.ext_type = 0;
+	m->m_flags &= ~M_EXT;
+	uma_zfree(zone_mbuf, m);
+}
+
+/*
+ * Attach the the cluster from *m to *n, set up m_ext in *n
+ * and bump the refcount of the cluster.
+ */
+static void
+mb_dupcl(struct mbuf *n, struct mbuf *m)
+{
+	KASSERT((m->m_flags & M_EXT) == M_EXT, ("%s: M_EXT not set", __func__));
+	KASSERT(m->m_ext.ref_cnt != NULL, ("%s: ref_cnt not set", __func__));
+	KASSERT((n->m_flags & M_EXT) == 0, ("%s: M_EXT set", __func__));
+
+	if (*(m->m_ext.ref_cnt) == 1)
+		*(m->m_ext.ref_cnt) += 1;
+	else
+		atomic_add_int(m->m_ext.ref_cnt, 1);
+	n->m_ext.ext_buf = m->m_ext.ext_buf;
+	n->m_ext.ext_free = m->m_ext.ext_free;
+	n->m_ext.ext_args = m->m_ext.ext_args;
+	n->m_ext.ext_size = m->m_ext.ext_size;
+	n->m_ext.ref_cnt = m->m_ext.ref_cnt;
+	n->m_ext.ext_type = m->m_ext.ext_type;
+	n->m_flags |= M_EXT;
+}
+
+/*
+ * 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
+m_demote(struct mbuf *m0, int all)
+{
+	struct mbuf *m;
+
+	for (m = all ? m0 : m0->m_next; m != NULL; m = m->m_next) {
+		if (m->m_flags & M_PKTHDR) {
+			m_tag_delete_chain(m, NULL);
+			m->m_flags &= ~M_PKTHDR;
+			bzero(&m->m_pkthdr, sizeof(struct pkthdr));
+		}
+		if (m->m_type == MT_HEADER)
+			m->m_type = MT_DATA;
+		if (m != m0 && m->m_nextpkt != NULL)
+			m->m_nextpkt = NULL;
+		m->m_flags = m->m_flags & (M_EXT|M_EOR|M_RDONLY|M_FREELIST);
+	}
+}
+
+/*
+ * 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
+m_sanity(struct mbuf *m0, int sanitize)
+#else
+m_sanity(PNATState pData, struct mbuf *m0, int sanitize)
+#endif
+{
+	struct mbuf *m;
+	caddr_t a, b;
+	int pktlen = 0;
+
+#ifdef INVARIANTS
+#define	M_SANITY_ACTION(s)	panic("mbuf %p: " s, m)
+#else
+#define	M_SANITY_ACTION(s)	printf("mbuf %p: " s, m)
+#endif
+
+	for (m = m0; m != NULL; m = m->m_next) {
+		/*
+		 * 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.
+		 */
+		a = ((m->m_flags & M_EXT) ? m->m_ext.ext_buf :
+			((m->m_flags & M_PKTHDR) ? (caddr_t)(&m->m_pktdat) :
+			 (caddr_t)(&m->m_dat)) );
+		b = (caddr_t)(a + (m->m_flags & M_EXT ? m->m_ext.ext_size :
+			((m->m_flags & M_PKTHDR) ? MHLEN : MLEN)));
+		if ((caddr_t)m->m_data < a)
+			M_SANITY_ACTION("m_data outside mbuf data range left");
+		if ((caddr_t)m->m_data > b)
+			M_SANITY_ACTION("m_data outside mbuf data range right");
+		if ((caddr_t)m->m_data + m->m_len > b)
+			M_SANITY_ACTION("m_data + m_len exeeds mbuf space");
+		if ((m->m_flags & M_PKTHDR) && m->m_pkthdr.header) {
+			if ((caddr_t)m->m_pkthdr.header < a ||
+			    (caddr_t)m->m_pkthdr.header > b)
+				M_SANITY_ACTION("m_pkthdr.header outside mbuf data range");
+		}
+
+		/* m->m_nextpkt may only be set on first mbuf in chain. */
+		if (m != m0 && m->m_nextpkt != NULL) {
+			if (sanitize) {
+#ifndef VBOX
+				m_freem(m->m_nextpkt);
+#else
+				m_freem(pData, m->m_nextpkt);
+#endif
+				m->m_nextpkt = (struct mbuf *)0xDEADC0DE;
+			} else
+				M_SANITY_ACTION("m->m_nextpkt on in-chain mbuf");
+		}
+
+		/* packet length (not mbuf length!) calculation */
+		if (m0->m_flags & M_PKTHDR)
+			pktlen += m->m_len;
+
+		/* m_tags may only be attached to first mbuf in chain. */
+		if (m != m0 && m->m_flags & M_PKTHDR &&
+		    !SLIST_EMPTY(&m->m_pkthdr.tags)) {
+			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 (m != m0 && m->m_flags & M_PKTHDR) {
+			if (sanitize) {
+				bzero(&m->m_pkthdr, sizeof(m->m_pkthdr));
+				m->m_flags &= ~M_PKTHDR;
+				/* put in 0xDEADCODE and leave hdr flag in */
+			} else
+				M_SANITY_ACTION("M_PKTHDR on in-chain mbuf");
+		}
+	}
+	m = m0;
+	if (pktlen && pktlen != m->m_pkthdr.len) {
+		if (sanitize)
+			m->m_pkthdr.len = 0;
+		else
+			M_SANITY_ACTION("m_pkthdr.len != mbuf chain length");
+	}
+	return 1;
+
+#undef	M_SANITY_ACTION
+}
+
+
+/*
+ * "Move" mbuf pkthdr from "from" to "to".
+ * "from" must have M_PKTHDR set, and "to" must be empty.
+ */
+void
+m_move_pkthdr(struct mbuf *to, struct mbuf *from)
+{
+
+#if 0
+	/* see below for why these are not enabled */
+	M_ASSERTPKTHDR(to);
+	/* Note: with MAC, this may not be a good assertion. */
+	KASSERT(SLIST_EMPTY(&to->m_pkthdr.tags),
+	    ("m_move_pkthdr: to has tags"));
+#endif
+#ifdef MAC
+	/*
+	 * XXXMAC: It could be this should also occur for non-MAC?
+	 */
+	if (to->m_flags & M_PKTHDR)
+		m_tag_delete_chain(to, NULL);
+#endif
+	to->m_flags = (from->m_flags & M_COPYFLAGS) | (to->m_flags & M_EXT);
+	if ((to->m_flags & M_EXT) == 0)
+		to->m_data = to->m_pktdat;
+	to->m_pkthdr = from->m_pkthdr;		/* especially tags */
+	SLIST_INIT(&from->m_pkthdr.tags);	/* purge tags from src */
+	from->m_flags &= ~M_PKTHDR;
+}
+
+/*
+ * 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
+m_dup_pkthdr(struct mbuf *to, struct mbuf *from, int how)
+{
+
+#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.
+	 */
+	M_ASSERTPKTHDR(to);
+	/* Note: with MAC, this may not be a good assertion. */
+	KASSERT(SLIST_EMPTY(&to->m_pkthdr.tags), ("m_dup_pkthdr: to has tags"));
+#endif
+	MBUF_CHECKSLEEP(how);
+#ifdef MAC
+	if (to->m_flags & M_PKTHDR)
+		m_tag_delete_chain(to, NULL);
+#endif
+	to->m_flags = (from->m_flags & M_COPYFLAGS) | (to->m_flags & M_EXT);
+	if ((to->m_flags & M_EXT) == 0)
+		to->m_data = to->m_pktdat;
+	to->m_pkthdr = from->m_pkthdr;
+	SLIST_INIT(&to->m_pkthdr.tags);
+	return (m_tag_copy_chain(to, from, MBTOM(how)));
+}
+
+/*
+ * Lesser-used path for M_PREPEND:
+ * allocate new mbuf to prepend to chain,
+ * copy junk along.
+ */
+struct mbuf *
+#ifndef VBOX
+m_prepend(struct mbuf *m, int len, int how)
+#else
+m_prepend(PNATState pData, struct mbuf *m, int len, int how)
+#endif
+{
+	struct mbuf *mn;
+
+	if (m->m_flags & M_PKTHDR)
+		MGETHDR(mn, how, m->m_type);
+	else
+		MGET(mn, how, m->m_type);
+	if (mn == NULL) {
+#ifndef VBOX
+		m_freem(m);
+#else
+		m_freem(pData, m);
+#endif
+		return (NULL);
+	}
+	if (m->m_flags & M_PKTHDR)
+		M_MOVE_PKTHDR(mn, m);
+	mn->m_next = m;
+	m = mn;
+	if(m->m_flags & M_PKTHDR) {
+		if (len < MHLEN)
+			MH_ALIGN(m, len);
+	} else {
+		if (len < MLEN)
+			M_ALIGN(m, len);
+	}
+	m->m_len = len;
+	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
+m_copym(struct mbuf *m, int off0, int len, int wait)
+#else
+m_copym(PNATState pData, struct mbuf *m, int off0, int len, int wait)
+#endif
+{
+	struct mbuf *n, **np;
+	int off = off0;
+	struct mbuf *top;
+	int copyhdr = 0;
+
+	KASSERT(off >= 0, ("m_copym, negative off %d", off));
+	KASSERT(len >= 0, ("m_copym, negative len %d", len));
+	MBUF_CHECKSLEEP(wait);
+	if (off == 0 && m->m_flags & M_PKTHDR)
+		copyhdr = 1;
+	while (off > 0) {
+		KASSERT(m != NULL, ("m_copym, offset > size of mbuf chain"));
+		if (off < m->m_len)
+			break;
+		off -= m->m_len;
+		m = m->m_next;
+	}
+	np = &top;
+	top = 0;
+	while (len > 0) {
+		if (m == NULL) {
+			KASSERT(len == M_COPYALL,
+			    ("m_copym, length > size of mbuf chain"));
+			break;
+		}
+		if (copyhdr)
+			MGETHDR(n, wait, m->m_type);
+		else
+			MGET(n, wait, m->m_type);
+		*np = n;
+		if (n == NULL)
+			goto nospace;
+		if (copyhdr) {
+			if (!m_dup_pkthdr(n, m, wait))
+				goto nospace;
+			if (len == M_COPYALL)
+				n->m_pkthdr.len -= off0;
+			else
+				n->m_pkthdr.len = len;
+			copyhdr = 0;
+		}
+		n->m_len = min(len, m->m_len - off);
+		if (m->m_flags & M_EXT) {
+			n->m_data = m->m_data + off;
+			mb_dupcl(n, m);
+		} else
+			bcopy(mtod(m, caddr_t)+off, mtod(n, caddr_t),
+			    (u_int)n->m_len);
+		if (len != M_COPYALL)
+			len -= n->m_len;
+		off = 0;
+		m = m->m_next;
+		np = &n->m_next;
+	}
+	if (top == NULL)
+		mbstat.m_mcfail++;	/* XXX: No consistency. */
+
+	return (top);
+nospace:
+#ifndef VBOX
+	m_freem(top);
+#else
+	m_freem(pData, top);
+#endif
+	mbstat.m_mcfail++;	/* XXX: No consistency. */
+	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
+m_bcopyxxx(void *s, void *t, u_int len)
+{
+	bcopy(s, t, (size_t)len);
+	return 0;
+}
+
+struct mbuf *
+#ifndef VBOX
+m_copymdata(struct mbuf *m, struct mbuf *n, int off, int len,
+    int prep, int how)
+#else
+m_copymdata(PNATState pData, struct mbuf *m, struct mbuf *n, int off, int len,
+    int prep, int how)
+#endif
+{
+	struct mbuf *mm, *x, *z, *prev = NULL;
+	caddr_t p;
+	int i, nlen = 0;
+	caddr_t buf[MLEN];
+
+	KASSERT(m != NULL && n != NULL, ("m_copymdata, no target or source"));
+	KASSERT(off >= 0, ("m_copymdata, negative off %d", off));
+	KASSERT(len >= 0, ("m_copymdata, negative len %d", len));
+	KASSERT(prep == 0 || prep == 1, ("m_copymdata, unknown direction %d", prep));
+
+	mm = m;
+	if (!prep) {
+		while(mm->m_next) {
+			prev = mm;
+			mm = mm->m_next;
+		}
+	}
+	for (z = n; z != NULL; z = z->m_next)
+		nlen += z->m_len;
+	if (len == M_COPYALL)
+		len = nlen - off;
+	if (off + len > nlen || len < 1)
+		return NULL;
+
+	if (!M_WRITABLE(mm)) {
+		/* XXX: Use proper m_xxx function instead. */
+#ifndef VBOX
+		x = m_getcl(how, MT_DATA, mm->m_flags);
+#else
+		x = m_getcl(pData, how, MT_DATA, mm->m_flags);
+#endif
+		if (x == NULL)
+			return NULL;
+		bcopy(mm->m_ext.ext_buf, x->m_ext.ext_buf, x->m_ext.ext_size);
+		p = x->m_ext.ext_buf + (mm->m_data - mm->m_ext.ext_buf);
+		x->m_data = p;
+		mm->m_next = NULL;
+		if (mm != m)
+			prev->m_next = x;
+#ifndef VBOX
+		m_free(mm);
+#else
+		m_free(pData, mm);
+#endif
+		mm = x;
+	}
+
+	/*
+	 * Append/prepend the data.  Allocating mbufs as necessary.
+	 */
+	/* Shortcut if enough free space in first/last mbuf. */
+	if (!prep && M_TRAILINGSPACE(mm) >= len) {
+		m_apply(n, off, len, m_bcopyxxx, mtod(mm, caddr_t) +
+			 mm->m_len);
+		mm->m_len += len;
+		mm->m_pkthdr.len += len;
+		return m;
+	}
+	if (prep && M_LEADINGSPACE(mm) >= len) {
+		mm->m_data = mtod(mm, caddr_t) - len;
+		m_apply(n, off, len, m_bcopyxxx, mtod(mm, caddr_t));
+		mm->m_len += len;
+		mm->m_pkthdr.len += len;
+		return mm;
+	}
+
+	/* Expand first/last mbuf to cluster if possible. */
+	if (!prep && !(mm->m_flags & M_EXT) && len > M_TRAILINGSPACE(mm)) {
+		bcopy(mm->m_data, &buf, mm->m_len);
+#ifndef VBOX
+		m_clget(mm, how);
+#else
+		m_clget(pData, mm, how);
+#endif
+		if (!(mm->m_flags & M_EXT))
+			return NULL;
+		bcopy(&buf, mm->m_ext.ext_buf, mm->m_len);
+		mm->m_data = mm->m_ext.ext_buf;
+		mm->m_pkthdr.header = NULL;
+	}
+	if (prep && !(mm->m_flags & M_EXT) && len > M_LEADINGSPACE(mm)) {
+		bcopy(mm->m_data, &buf, mm->m_len);
+#ifndef VBOX
+		m_clget(mm, how);
+#else
+		m_clget(pData, mm, how);
+#endif
+		if (!(mm->m_flags & M_EXT))
+			return NULL;
+		bcopy(&buf, (caddr_t *)mm->m_ext.ext_buf +
+		       mm->m_ext.ext_size - mm->m_len, mm->m_len);
+		mm->m_data = (caddr_t)mm->m_ext.ext_buf +
+			      mm->m_ext.ext_size - mm->m_len;
+		mm->m_pkthdr.header = NULL;
+	}
+
+	/* Append/prepend as many mbuf (clusters) as necessary to fit len. */
+	if (!prep && len > M_TRAILINGSPACE(mm)) {
+		if (!m_getm(mm, len - M_TRAILINGSPACE(mm), how, MT_DATA))
+			return NULL;
+	}
+	if (prep && len > M_LEADINGSPACE(mm)) {
+		if (!(z = m_getm(NULL, len - M_LEADINGSPACE(mm), how, MT_DATA)))
+			return NULL;
+		i = 0;
+		for (x = z; x != NULL; x = x->m_next) {
+			i += x->m_flags & M_EXT ? x->m_ext.ext_size :
+			      (x->m_flags & M_PKTHDR ? MHLEN : MLEN);
+			if (!x->m_next)
+				break;
+		}
+		z->m_data += i - len;
+		m_move_pkthdr(mm, z);
+		x->m_next = mm;
+		mm = z;
+	}
+
+	/* Seek to start position in source mbuf. Optimization for long chains. */
+	while (off > 0) {
+		if (off < n->m_len)
+			break;
+		off -= n->m_len;
+		n = n->m_next;
+	}
+
+	/* Copy data into target mbuf. */
+	z = mm;
+	while (len > 0) {
+		KASSERT(z != NULL, ("m_copymdata, falling off target edge"));
+		i = M_TRAILINGSPACE(z);
+		m_apply(n, off, i, m_bcopyxxx, mtod(z, caddr_t) + z->m_len);
+		z->m_len += i;
+		/* fixup pkthdr.len if necessary */
+		if ((prep ? mm : m)->m_flags & M_PKTHDR)
+			(prep ? mm : m)->m_pkthdr.len += i;
+		off += i;
+		len -= i;
+		z = z->m_next;
+	}
+	return (prep ? mm : m);
+}
+
+/*
+ * 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
+m_copypacket(struct mbuf *m, int how)
+#else
+m_copypacket(PNATState pData, struct mbuf *m, int how)
+#endif
+{
+	struct mbuf *top, *n, *o;
+
+	MBUF_CHECKSLEEP(how);
+	MGET(n, how, m->m_type);
+	top = n;
+	if (n == NULL)
+		goto nospace;
+
+	if (!m_dup_pkthdr(n, m, how))
+		goto nospace;
+	n->m_len = m->m_len;
+	if (m->m_flags & M_EXT) {
+		n->m_data = m->m_data;
+		mb_dupcl(n, m);
+	} else {
+		n->m_data = n->m_pktdat + (m->m_data - m->m_pktdat );
+		bcopy(mtod(m, char *), mtod(n, char *), n->m_len);
+	}
+
+	m = m->m_next;
+	while (m) {
+		MGET(o, how, m->m_type);
+		if (o == NULL)
+			goto nospace;
+
+		n->m_next = o;
+		n = n->m_next;
+
+		n->m_len = m->m_len;
+		if (m->m_flags & M_EXT) {
+			n->m_data = m->m_data;
+			mb_dupcl(n, m);
+		} else {
+			bcopy(mtod(m, char *), mtod(n, char *), n->m_len);
+		}
+
+		m = m->m_next;
+	}
+	return top;
+nospace:
+#ifndef VBOX
+	m_freem(top);
+#else
+	m_freem(pData, top);
+#endif
+	mbstat.m_mcfail++;	/* XXX: No consistency. */
+	return (NULL);
+}
+
+/*
+ * Copy data from an mbuf chain starting "off" bytes from the beginning,
+ * continuing for "len" bytes, into the indicated buffer.
+ */
+void
+m_copydata(const struct mbuf *m, int off, int len, caddr_t cp)
+{
+	u_int count;
+
+	KASSERT(off >= 0, ("m_copydata, negative off %d", off));
+	KASSERT(len >= 0, ("m_copydata, negative len %d", len));
+	while (off > 0) {
+		KASSERT(m != NULL, ("m_copydata, offset > size of mbuf chain"));
+		if (off < m->m_len)
+			break;
+		off -= m->m_len;
+		m = m->m_next;
+	}
+	while (len > 0) {
+		KASSERT(m != NULL, ("m_copydata, length > size of mbuf chain"));
+		count = min(m->m_len - off, len);
+		bcopy(mtod(m, caddr_t) + off, cp, count);
+		len -= count;
+		cp += count;
+		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
+m_dup(struct mbuf *m, int how)
+#else
+m_dup(PNATState pData, struct mbuf *m, int how)
+#endif
+{
+	struct mbuf **p, *top = NULL;
+	int remain, moff, nsize;
+
+	MBUF_CHECKSLEEP(how);
+	/* 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 */
+	remain = m->m_pkthdr.len;
+	moff = 0;
+	p = &top;
+	while (remain > 0 || top == NULL) {	/* allow m->m_pkthdr.len == 0 */
+		struct mbuf *n;
+
+		/* Get the next new mbuf */
+		if (remain >= MINCLSIZE) {
+#ifndef VBOX
+			n = m_getcl(how, m->m_type, 0);
+#else
+			n = m_getcl(pData, how, m->m_type, 0);
+#endif
+			nsize = MCLBYTES;
+		} else {
+#ifndef VBOX
+			n = m_get(how, m->m_type);
+#else
+			n = m_get(pData, how, m->m_type);
+#endif
+			nsize = MLEN;
+		}
+		if (n == NULL)
+			goto nospace;
+
+		if (top == NULL) {		/* First one, must be PKTHDR */
+			if (!m_dup_pkthdr(n, m, how)) {
+#ifndef VBOX
+				m_free(n);
+#else
+				m_free(pData, n);
+#endif
+				goto nospace;
+			}
+			if ((n->m_flags & M_EXT) == 0)
+				nsize = MHLEN;
+		}
+		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 */
+		while (n->m_len < nsize && m != NULL) {
+			int chunk = min(nsize - n->m_len, m->m_len - moff);
+
+			bcopy(m->m_data + moff, n->m_data + n->m_len, chunk);
+			moff += chunk;
+			n->m_len += chunk;
+			remain -= chunk;
+			if (moff == m->m_len) {
+				m = m->m_next;
+				moff = 0;
+			}
+		}
+
+		/* Check correct total mbuf length */
+		KASSERT((remain > 0 && m != NULL) || (remain == 0 && m == NULL),
+		    	("%s: bogus m_pkthdr.len", __func__));
+	}
+	return (top);
+
+nospace:
+#ifndef VBOX
+	m_freem(top);
+#else
+	m_freem(pData, top);
+#endif
+	mbstat.m_mcfail++;	/* XXX: No consistency. */
+	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
+m_cat(struct mbuf *m, struct mbuf *n)
+#else
+m_cat(PNATState pData, struct mbuf *m, struct mbuf *n)
+#endif
+{
+	while (m->m_next)
+		m = m->m_next;
+	while (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 */
+			m->m_next = n;
+			return;
+		}
+		/* splat the data from one into the other */
+		bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
+		    (u_int)n->m_len);
+		m->m_len += n->m_len;
+#ifndef VBOX
+		n = m_free(n);
+#else
+		n = m_free(pData, n);
+#endif
+	}
+}
+
+void
+#ifndef VBOX
+m_adj(struct mbuf *mp, int req_len)
+#else
+m_adj(PNATState pData, struct mbuf *mp, int req_len)
+#endif
+{
+	int len = req_len;
+	struct mbuf *m;
+	int count;
+
+	if ((m = mp) == NULL)
+		return;
+	if (len >= 0) {
+		/*
+		 * Trim from head.
+		 */
+		while (m != NULL && len > 0) {
+			if (m->m_len <= len) {
+				len -= m->m_len;
+				m->m_len = 0;
+				m = m->m_next;
+			} else {
+				m->m_len -= len;
+				m->m_data += len;
+				len = 0;
+			}
+		}
+		m = mp;
+		if (mp->m_flags & M_PKTHDR)
+			m->m_pkthdr.len -= (req_len - len);
+	} 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.
+		 */
+		len = -len;
+		count = 0;
+		for (;;) {
+			count += m->m_len;
+			if (m->m_next == (struct mbuf *)0)
+				break;
+			m = m->m_next;
+		}
+		if (m->m_len >= len) {
+			m->m_len -= len;
+			if (mp->m_flags & M_PKTHDR)
+				mp->m_pkthdr.len -= len;
+			return;
+		}
+		count -= len;
+		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;
+		if (m->m_flags & M_PKTHDR)
+			m->m_pkthdr.len = count;
+		for (; m; m = m->m_next) {
+			if (m->m_len >= count) {
+				m->m_len = count;
+				if (m->m_next != NULL) {
+#ifndef VBOX
+					m_freem(m->m_next);
+#else
+					m_freem(pData, m->m_next);
+#endif
+					m->m_next = NULL;
+				}
+				break;
+			}
+			count -= m->m_len;
+		}
+	}
+}
+
+/*
+ * 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
+m_pullup(struct mbuf *n, int len)
+#else
+m_pullup(PNATState pData, struct mbuf *n, int len)
+#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.
+	 */
+	if ((n->m_flags & M_EXT) == 0 &&
+	    n->m_data + len < &n->m_dat[MLEN] && n->m_next) {
+		if (n->m_len >= len)
+			return (n);
+		m = n;
+		n = n->m_next;
+		len -= m->m_len;
+	} else {
+		if (len > MHLEN)
+			goto bad;
+		MGET(m, M_DONTWAIT, n->m_type);
+		if (m == NULL)
+			goto bad;
+		m->m_len = 0;
+		if (n->m_flags & M_PKTHDR)
+			M_MOVE_PKTHDR(m, n);
+	}
+	space = &m->m_dat[MLEN] - (m->m_data + m->m_len);
+	do {
+		count = min(min(max(len, max_protohdr), space), n->m_len);
+		bcopy(mtod(n, caddr_t), mtod(m, caddr_t) + m->m_len,
+		  (u_int)count);
+		len -= count;
+		m->m_len += count;
+		n->m_len -= count;
+		space -= count;
+		if (n->m_len)
+			n->m_data += count;
+		else
+#ifndef VBOX
+			n = m_free(n);
+#else
+			n = m_free(pData, n);
+#endif
+	} while (len > 0 && n);
+	if (len > 0) {
+#ifndef VBOX
+		(void) m_free(m);
+#else
+		(void) m_free(pData, m);
+#endif
+		goto bad;
+	}
+	m->m_next = n;
+	return (m);
+bad:
+#ifndef VBOX
+	m_freem(n);
+#else
+	m_freem(pData, n);
+#endif
+	mbstat.m_mpfail++;	/* XXX: No consistency. */
+	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
+m_copyup(struct mbuf *n, int len, int dstoff)
+#else
+m_copyup(PNATState pData, struct mbuf *n, int len, int dstoff)
+#endif
+{
+	struct mbuf *m;
+	int count, space;
+
+	if (len > (MHLEN - dstoff))
+		goto bad;
+	MGET(m, M_DONTWAIT, n->m_type);
+	if (m == NULL)
+		goto bad;
+	m->m_len = 0;
+	if (n->m_flags & M_PKTHDR)
+		M_MOVE_PKTHDR(m, n);
+	m->m_data += dstoff;
+	space = &m->m_dat[MLEN] - (m->m_data + m->m_len);
+	do {
+		count = min(min(max(len, max_protohdr), space), n->m_len);
+		memcpy(mtod(m, caddr_t) + m->m_len, mtod(n, caddr_t),
+		    (unsigned)count);
+		len -= count;
+		m->m_len += count;
+		n->m_len -= count;
+		space -= count;
+		if (n->m_len)
+			n->m_data += count;
+		else
+#ifndef VBOX
+			n = m_free(n);
+#else
+			n = m_free(pData, n);
+#endif
+	} while (len > 0 && n);
+	if (len > 0) {
+#ifndef VBOX
+		(void) m_free(m);
+#else
+		(void) m_free(pData, m);
+#endif
+		goto bad;
+	}
+	m->m_next = n;
+	return (m);
+ bad:
+#ifndef VBOX
+	m_freem(n);
+#else
+	m_freem(pData, n);
+#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
+m_split(struct mbuf *m0, int len0, int wait)
+#else
+m_split(PNATState pData, struct mbuf *m0, int len0, int wait)
+#endif
+{
+	struct mbuf *m, *n;
+	u_int len = len0, remain;
+
+	MBUF_CHECKSLEEP(wait);
+	for (m = m0; m && len > m->m_len; m = m->m_next)
+		len -= m->m_len;
+	if (m == NULL)
+		return (NULL);
+	remain = m->m_len - len;
+	if (m0->m_flags & M_PKTHDR) {
+		MGETHDR(n, wait, m0->m_type);
+		if (n == NULL)
+			return (NULL);
+		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)
+			goto extpacket;
+		if (remain > MHLEN) {
+			/* m can't be the lead packet */
+			MH_ALIGN(n, 0);
+#ifndef VBOX
+			n->m_next = m_split(m, len, wait);
+#else
+			n->m_next = m_split(pData, m, len, wait);
+#endif
+			if (n->m_next == NULL) {
+#ifndef VBOX
+				(void) m_free(n);
+#else
+				(void) m_free(pData, n);
+#endif
+				return (NULL);
+			} else {
+				n->m_len = 0;
+				return (n);
+			}
+		} else
+			MH_ALIGN(n, remain);
+	} else if (remain == 0) {
+		n = m->m_next;
+		m->m_next = NULL;
+		return (n);
+	} else {
+		MGET(n, wait, m->m_type);
+		if (n == NULL)
+			return (NULL);
+		M_ALIGN(n, remain);
+	}
+extpacket:
+	if (m->m_flags & M_EXT) {
+		n->m_data = m->m_data + len;
+		mb_dupcl(n, m);
+	} else {
+		bcopy(mtod(m, caddr_t) + len, mtod(n, caddr_t), remain);
+	}
+	n->m_len = remain;
+	m->m_len = len;
+	n->m_next = m->m_next;
+	m->m_next = NULL;
+	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 *
+m_devget(char *buf, int totlen, int off, struct ifnet *ifp,
+    void (*copy)(char *from, caddr_t to, u_int len))
+{
+	struct mbuf *m;
+	struct mbuf *top = NULL, **mp = &top;
+	int len;
+
+	if (off < 0 || off > MHLEN)
+		return (NULL);
+
+	while (totlen > 0) {
+		if (top == NULL) {	/* First one, must be PKTHDR */
+			if (totlen + off >= MINCLSIZE) {
+				m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
+				len = MCLBYTES;
+			} else {
+				m = m_gethdr(M_DONTWAIT, MT_DATA);
+				len = MHLEN;
+
+				/* Place initial small packet/header at end of mbuf */
+				if (m && totlen + off + max_linkhdr <= MLEN) {
+					m->m_data += max_linkhdr;
+					len -= max_linkhdr;
+				}
+			}
+			if (m == NULL)
+				return NULL;
+			m->m_pkthdr.rcvif = ifp;
+			m->m_pkthdr.len = totlen;
+		} else {
+			if (totlen + off >= MINCLSIZE) {
+				m = m_getcl(M_DONTWAIT, MT_DATA, 0);
+				len = MCLBYTES;
+			} else {
+				m = m_get(M_DONTWAIT, MT_DATA);
+				len = MLEN;
+			}
+			if (m == NULL) {
+				m_freem(top);
+				return NULL;
+			}
+		}
+		if (off) {
+			m->m_data += off;
+			len -= off;
+			off = 0;
+		}
+		m->m_len = len = min(totlen, len);
+		if (copy)
+			copy(buf, mtod(m, caddr_t), (u_int)len);
+		else
+			bcopy(buf, mtod(m, caddr_t), (u_int)len);
+		buf += len;
+		*mp = m;
+		mp = &m->m_next;
+		totlen -= len;
+	}
+	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
+m_copyback(struct mbuf *m0, int off, int len, c_caddr_t cp)
+#else
+m_copyback(PNATState pData, struct mbuf *m0, int off, int len, c_caddr_t cp)
+#endif
+{
+	int mlen;
+	struct mbuf *m = m0, *n;
+	int totlen = 0;
+
+	if (m0 == NULL)
+		return;
+	while (off > (mlen = m->m_len)) {
+		off -= mlen;
+		totlen += mlen;
+		if (m->m_next == NULL) {
+#ifndef VBOX
+			n = m_get(M_DONTWAIT, m->m_type);
+#else
+			n = m_get(pData, M_DONTWAIT, m->m_type);
+#endif
+			if (n == NULL)
+				goto out;
+			bzero(mtod(n, caddr_t), MLEN);
+			n->m_len = min(MLEN, len + off);
+			m->m_next = n;
+		}
+		m = m->m_next;
+	}
+	while (len > 0) {
+		if (m->m_next == NULL && (len > m->m_len - off)) {
+			m->m_len += min(len - (m->m_len - off),
+			    M_TRAILINGSPACE(m));
+		}
+		mlen = min (m->m_len - off, len);
+		bcopy(cp, off + mtod(m, caddr_t), (u_int)mlen);
+		cp += mlen;
+		len -= mlen;
+		mlen += off;
+		off = 0;
+		totlen += mlen;
+		if (len == 0)
+			break;
+		if (m->m_next == NULL) {
+#ifndef VBOX
+			n = m_get(M_DONTWAIT, m->m_type);
+#else
+			n = m_get(pData, M_DONTWAIT, m->m_type);
+#endif
+			if (n == NULL)
+				break;
+			n->m_len = min(MLEN, len);
+			m->m_next = n;
+		}
+		m = m->m_next;
+	}
+out:	if (((m = m0)->m_flags & M_PKTHDR) && (m->m_pkthdr.len < totlen))
+		m->m_pkthdr.len = totlen;
+}
+
+/*
+ * 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
+m_append(struct mbuf *m0, int len, c_caddr_t cp)
+#else
+m_append(PNATState pData, struct mbuf *m0, int len, c_caddr_t cp)
+#endif
+{
+	struct mbuf *m, *n;
+	int remainder, space;
+
+	for (m = m0; m->m_next != NULL; m = m->m_next)
+		;
+	remainder = len;
+	space = M_TRAILINGSPACE(m);
+	if (space > 0) {
+		/*
+		 * Copy into available space.
+		 */
+		if (space > remainder)
+			space = remainder;
+		bcopy(cp, mtod(m, caddr_t) + m->m_len, space);
+		m->m_len += space;
+		cp += space, remainder -= space;
+	}
+	while (remainder > 0) {
+		/*
+		 * Allocate a new mbuf; could check space
+		 * and allocate a cluster instead.
+		 */
+#ifndef VBOX
+		n = m_get(M_DONTWAIT, m->m_type);
+#else
+		n = m_get(pData, M_DONTWAIT, m->m_type);
+#endif
+		if (n == NULL)
+			break;
+		n->m_len = min(MLEN, remainder);
+		bcopy(cp, mtod(n, caddr_t), n->m_len);
+		cp += n->m_len, remainder -= n->m_len;
+		m->m_next = n;
+		m = n;
+	}
+	if (m0->m_flags & M_PKTHDR)
+		m0->m_pkthdr.len += len - remainder;
+	return (remainder == 0);
+}
+
+/*
+ * Apply function f to the data in an mbuf chain starting "off" bytes from
+ * the beginning, continuing for "len" bytes.
+ */
+int
+m_apply(struct mbuf *m, int off, int len,
+    int (*f)(void *, void *, u_int), void *arg)
+{
+	u_int count;
+	int rval;
+
+	KASSERT(off >= 0, ("m_apply, negative off %d", off));
+	KASSERT(len >= 0, ("m_apply, negative len %d", len));
+	while (off > 0) {
+		KASSERT(m != NULL, ("m_apply, offset > size of mbuf chain"));
+		if (off < m->m_len)
+			break;
+		off -= m->m_len;
+		m = m->m_next;
+	}
+	while (len > 0) {
+		KASSERT(m != NULL, ("m_apply, offset > size of mbuf chain"));
+		count = min(m->m_len - off, len);
+		rval = (*f)(arg, mtod(m, caddr_t) + off, count);
+		if (rval)
+			return (rval);
+		len -= count;
+		off = 0;
+		m = m->m_next;
+	}
+	return (0);
+}
+
+/*
+ * Return a pointer to mbuf/offset of location in mbuf chain.
+ */
+struct mbuf *
+m_getptr(struct mbuf *m, int loc, int *off)
+{
+
+	while (loc >= 0) {
+		/* Normal end of search. */
+		if (m->m_len > loc) {
+			*off = loc;
+			return (m);
+		} else {
+			loc -= m->m_len;
+			if (m->m_next == NULL) {
+				if (loc == 0) {
+					/* Point at the end of valid data. */
+					*off = m->m_len;
+					return (m);
+				}
+				return (NULL);
+			}
+			m = m->m_next;
+		}
+	}
+	return (NULL);
+}
+
+void
+m_print(const struct mbuf *m, int maxlen)
+{
+	int len;
+	int pdata;
+	const struct mbuf *m2;
+
+	if (m->m_flags & M_PKTHDR)
+		len = m->m_pkthdr.len;
+	else
+		len = -1;
+	m2 = m;
+	while (m2 != NULL && (len == -1 || len)) {
+		pdata = m2->m_len;
+		if (maxlen != -1 && pdata > maxlen)
+			pdata = maxlen;
+		printf("mbuf: %p len: %d, next: %p, %b%s", m2, m2->m_len,
+		    m2->m_next, m2->m_flags, "\20\20freelist\17skipfw"
+		    "\11proto5\10proto4\7proto3\6proto2\5proto1\4rdonly"
+		    "\3eor\2pkthdr\1ext", pdata ? "" : "\n");
+		if (pdata)
+			printf(", %*D\n", pdata, (u_char *)m2->m_data, "-");
+		if (len != -1)
+			len -= m2->m_len;
+		m2 = m2->m_next;
+	}
+	if (len > 0)
+		printf("%d bytes unaccounted for.\n", len);
+	return;
+}
+
+u_int
+m_fixhdr(struct mbuf *m0)
+{
+	u_int len;
+
+	len = m_length(m0, NULL);
+	m0->m_pkthdr.len = len;
+	return (len);
+}
+
+u_int
+m_length(struct mbuf *m0, struct mbuf **last)
+{
+	struct mbuf *m;
+	u_int len;
+
+	len = 0;
+	for (m = m0; m != NULL; m = m->m_next) {
+		len += m->m_len;
+		if (m->m_next == NULL)
+			break;
+	}
+	if (last != NULL)
+		*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
+m_defrag(struct mbuf *m0, int how)
+#else
+m_defrag(PNATState pData, struct mbuf *m0, int how)
+#endif
+{
+	struct mbuf *m_new = NULL, *m_final = NULL;
+	int progress = 0, length;
+
+	MBUF_CHECKSLEEP(how);
+	if (!(m0->m_flags & M_PKTHDR))
+		return (m0);
+
+	m_fixhdr(m0); /* Needed sanity check */
+
+#ifdef MBUF_STRESS_TEST
+	if (m_defragrandomfailures) {
+		int temp = arc4random() & 0xff;
+		if (temp == 0xba)
+			goto nospace;
+	}
+#endif
+
+	if (m0->m_pkthdr.len > MHLEN)
+#ifndef VBOX
+		m_final = m_getcl(how, MT_DATA, M_PKTHDR);
+#else
+		m_final = m_getcl(pData, how, MT_DATA, M_PKTHDR);
+#endif
+	else
+#ifndef VBOX
+		m_final = m_gethdr(how, MT_DATA);
+#else
+		m_final = m_gethdr(pData, how, MT_DATA);
+#endif
+
+	if (m_final == NULL)
+		goto nospace;
+
+	if (m_dup_pkthdr(m_final, m0, how) == 0)
+		goto nospace;
+
+	m_new = m_final;
+
+	while (progress < m0->m_pkthdr.len) {
+		length = m0->m_pkthdr.len - progress;
+		if (length > MCLBYTES)
+			length = MCLBYTES;
+
+		if (m_new == NULL) {
+			if (length > MLEN)
+#ifndef VBOX
+				m_new = m_getcl(how, MT_DATA, 0);
+#else
+				m_new = m_getcl(pData, how, MT_DATA, 0);
+#endif
+			else
+#ifndef VBOX
+				m_new = m_get(how, MT_DATA);
+#else
+				m_new = m_get(pData, how, MT_DATA);
+#endif
+			if (m_new == NULL)
+				goto nospace;
+		}
+
+		m_copydata(m0, progress, length, mtod(m_new, caddr_t));
+		progress += length;
+		m_new->m_len = length;
+		if (m_new != m_final)
+#ifndef VBOX
+			m_cat(m_final, m_new);
+#else
+			m_cat(pData, m_final, m_new);
+#endif
+		m_new = NULL;
+	}
+#ifdef MBUF_STRESS_TEST
+	if (m0->m_next == NULL)
+		m_defraguseless++;
+#endif
+#ifndef VBOX
+	m_freem(m0);
+#else
+	m_freem(pData, m0);
+#endif
+	m0 = m_final;
+#ifdef MBUF_STRESS_TEST
+	m_defragpackets++;
+	m_defragbytes += m0->m_pkthdr.len;
+#endif
+	return (m0);
+nospace:
+#ifdef MBUF_STRESS_TEST
+	m_defragfailure++;
+#endif
+	if (m_final)
+#ifndef VBOX
+		m_freem(m_final);
+#else
+		m_freem(pData, m_final);
+#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
+m_collapse(struct mbuf *m0, int how, int maxfrags)
+#else
+m_collapse(PNATState pData, struct mbuf *m0, int how, int maxfrags)
+#endif
+{
+	struct mbuf *m, *n, *n2, **prev;
+	u_int curfrags;
+
+	/*
+	 * Calculate the current number of frags.
+	 */
+	curfrags = 0;
+	for (m = m0; m != NULL; m = m->m_next)
+		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;
+again:
+	for (;;) {
+		n = m->m_next;
+		if (n == NULL)
+			break;
+		if ((m->m_flags & M_RDONLY) == 0 &&
+		    n->m_len < M_TRAILINGSPACE(m)) {
+			bcopy(mtod(n, void *), mtod(m, char *) + m->m_len,
+				n->m_len);
+			m->m_len += n->m_len;
+			m->m_next = n->m_next;
+#ifndef VBOX
+			m_free(n);
+#else
+			m_free(pData, n);
+#endif
+			if (--curfrags <= maxfrags)
+				return m0;
+		} else
+			m = n;
+	}
+	KASSERT(maxfrags > 1,
+		("maxfrags %u, but normal collapse failed", maxfrags));
+	/*
+	 * Collapse consecutive mbufs to a cluster.
+	 */
+	prev = &m0->m_next;		/* NB: not the first mbuf */
+	while ((n = *prev) != NULL) {
+		if ((n2 = n->m_next) != NULL &&
+		    n->m_len + n2->m_len < MCLBYTES) {
+#ifndef VBOX
+			m = m_getcl(how, MT_DATA, 0);
+#else
+			m = m_getcl(pData, how, MT_DATA, 0);
+#endif
+			if (m == NULL)
+				goto bad;
+			bcopy(mtod(n, void *), mtod(m, void *), n->m_len);
+			bcopy(mtod(n2, void *), mtod(m, char *) + n->m_len,
+				n2->m_len);
+			m->m_len = n->m_len + n2->m_len;
+			m->m_next = n2->m_next;
+			*prev = m;
+#ifndef VBOX
+			m_free(n);
+			m_free(n2);
+#else
+			m_free(pData, n);
+			m_free(pData, n2);
+#endif
+			if (--curfrags <= maxfrags)	/* +1 cl -2 mbufs */
+				return m0;
+			/*
+			 * Still not there, try the normal collapse
+			 * again before we allocate another cluster.
+			 */
+			goto again;
+		}
+		prev = &n->m_next;
+	}
+	/*
+	 * 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 *
+m_fragment(struct mbuf *m0, int how, int length)
+{
+	struct mbuf *m_new = NULL, *m_final = NULL;
+	int progress = 0;
+
+	if (!(m0->m_flags & M_PKTHDR))
+		return (m0);
+
+	if ((length == 0) || (length < -2))
+		return (m0);
+
+	m_fixhdr(m0); /* Needed sanity check */
+
+	m_final = m_getcl(how, MT_DATA, M_PKTHDR);
+
+	if (m_final == NULL)
+		goto nospace;
+
+	if (m_dup_pkthdr(m_final, m0, how) == 0)
+		goto nospace;
+
+	m_new = m_final;
+
+	if (length == -1)
+		length = 1 + (arc4random() & 255);
+
+	while (progress < m0->m_pkthdr.len) {
+		int fraglen;
+
+		if (length > 0)
+			fraglen = length;
+		else
+			fraglen = 1 + (arc4random() & 255);
+		if (fraglen > m0->m_pkthdr.len - progress)
+			fraglen = m0->m_pkthdr.len - progress;
+
+		if (fraglen > MCLBYTES)
+			fraglen = MCLBYTES;
+
+		if (m_new == NULL) {
+			m_new = m_getcl(how, MT_DATA, 0);
+			if (m_new == NULL)
+				goto nospace;
+		}
+
+		m_copydata(m0, progress, fraglen, mtod(m_new, caddr_t));
+		progress += fraglen;
+		m_new->m_len = fraglen;
+		if (m_new != m_final)
+			m_cat(m_final, m_new);
+		m_new = NULL;
+	}
+	m_freem(m0);
+	m0 = m_final;
+	return (m0);
+nospace:
+	if (m_final)
+		m_freem(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 *
+m_uiotombuf(struct uio *uio, int how, int len, int align, int flags)
+{
+	struct mbuf *m, *mb;
+	int error, length, total;
+	int progress = 0;
+
+	/*
+	 * len can be zero or an arbitrary large value bound by
+	 * the total data supplied by the uio.
+	 */
+	if (len > 0)
+		total = min(uio->uio_resid, len);
+	else
+		total = uio->uio_resid;
+
+	/*
+	 * The smallest unit returned by m_getm2() is a single mbuf
+	 * with pkthdr.  We can't align past it.
+	 */
+	if (align >= MHLEN)
+		return (NULL);
+
+	/*
+	 * Give us the full allocation or nothing.
+	 * If len is zero return the smallest empty mbuf.
+	 */
+	m = m_getm2(NULL, max(total + align, 1), how, MT_DATA, flags);
+	if (m == NULL)
+		return (NULL);
+	m->m_data += align;
+
+	/* Fill all mbufs with uio data and update header information. */
+	for (mb = m; mb != NULL; mb = mb->m_next) {
+		length = min(M_TRAILINGSPACE(mb), total - progress);
+
+		error = uiomove(mtod(mb, void *), length, uio);
+		if (error) {
+			m_freem(m);
+			return (NULL);
+		}
+
+		mb->m_len = length;
+		progress += length;
+		if (flags & M_PKTHDR)
+			m->m_pkthdr.len += length;
+	}
+	KASSERT(progress == total, ("%s: progress != total", __func__));
+
+	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
+m_align(struct mbuf *m, int len)
+{
+	int adjust;
+
+	if (m->m_flags & M_EXT)
+		adjust = m->m_ext.ext_size - len;
+	else if (m->m_flags & M_PKTHDR)
+		adjust = MHLEN - len;
+	else
+		adjust = MLEN - len;
+	m->m_data += adjust &~ (sizeof(long)-1);
+}
+
+/*
+ * 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
+m_unshare(struct mbuf *m0, int how)
+#else
+m_unshare(PNATState pData, struct mbuf *m0, int how)
+#endif
+{
+	struct mbuf *m, *mprev;
+	struct mbuf *n, *mfirst, *mlast;
+	int len, off;
+
+	mprev = NULL;
+	for (m = m0; m != NULL; m = mprev->m_next) {
+		/*
+		 * 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.
+		 */
+		if ((m->m_flags & M_EXT) == 0) {
+			if (mprev && (mprev->m_flags & M_EXT) &&
+			    m->m_len <= M_TRAILINGSPACE(mprev)) {
+				/* XXX: this ignores mbuf types */
+				memcpy(mtod(mprev, caddr_t) + mprev->m_len,
+				       mtod(m, caddr_t), m->m_len);
+				mprev->m_len += m->m_len;
+				mprev->m_next = m->m_next;	/* unlink from chain */
+#ifndef VBOX
+				m_free(m);			/* reclaim mbuf */
+#else
+				m_free(pData, m);			/* reclaim mbuf */
+#endif
+#if 0
+				newipsecstat.ips_mbcoalesced++;
+#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).
+		 */
+		KASSERT(m->m_flags & M_EXT, ("m_flags 0x%x", m->m_flags));
+		/* NB: we only coalesce into a cluster or larger */
+		if (mprev != NULL && (mprev->m_flags & M_EXT) &&
+		    m->m_len <= M_TRAILINGSPACE(mprev)) {
+			/* XXX: this ignores mbuf types */
+			memcpy(mtod(mprev, caddr_t) + mprev->m_len,
+			       mtod(m, caddr_t), m->m_len);
+			mprev->m_len += m->m_len;
+			mprev->m_next = m->m_next;	/* unlink from chain */
+#ifndef VBOX
+			m_free(m);			/* reclaim mbuf */
+#else
+			m_free(pData, m);			/* reclaim mbuf */
+#endif
+#if 0
+			newipsecstat.ips_clcoalesced++;
+#endif
+			continue;
+		}
+
+		/*
+		 * Allocate new space to hold the copy...
+		 */
+		/* XXX why can M_PKTHDR be set past the first mbuf? */
+		if (mprev == NULL && (m->m_flags & M_PKTHDR)) {
+			/*
+			 * 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.
+			 */
+			MGETHDR(n, how, m->m_type);
+			if (n == NULL) {
+#ifndef VBOX
+				m_freem(m0);
+#else
+				m_freem(pData, m0);
+#endif
+				return (NULL);
+			}
+			M_MOVE_PKTHDR(n, m);
+			MCLGET(n, how);
+			if ((n->m_flags & M_EXT) == 0) {
+#ifndef VBOX
+				m_free(n);
+				m_freem(m0);
+#else
+				m_free(pData, n);
+				m_freem(pData, m0);
+#endif
+				return (NULL);
+			}
+		} else {
+#ifndef VBOX
+			n = m_getcl(how, m->m_type, m->m_flags);
+#else
+			n = m_getcl(pData, how, m->m_type, m->m_flags);
+#endif
+			if (n == NULL) {
+#ifndef VBOX
+				m_freem(m0);
+#else
+				m_freem(pData, m0);
+#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.
+		 */
+		len = m->m_len;
+		off = 0;
+		mfirst = n;
+		mlast = NULL;
+		for (;;) {
+			int cc = min(len, MCLBYTES);
+			memcpy(mtod(n, caddr_t), mtod(m, caddr_t) + off, cc);
+			n->m_len = cc;
+			if (mlast != NULL)
+				mlast->m_next = n;
+			mlast = n;
+#if 0
+			newipsecstat.ips_clcopied++;
+#endif
+
+			len -= cc;
+			if (len <= 0)
+				break;
+			off += cc;
+
+#ifndef VBOX
+			n = m_getcl(how, m->m_type, m->m_flags);
+#else
+			n = m_getcl(pData, how, m->m_type, m->m_flags);
+#endif
+			if (n == NULL) {
+#ifndef VBOX
+				m_freem(mfirst);
+				m_freem(m0);
+#else
+				m_freem(pData, mfirst);
+				m_freem(pData, m0);
+#endif
+				return (NULL);
+			}
+		}
+		n->m_next = m->m_next;
+		if (mprev == NULL)
+			m0 = mfirst;		/* new head of chain */
+		else
+			mprev->m_next = mfirst;	/* replace old mbuf */
+#ifndef VBOX
+		m_free(m);			/* release old mbuf */
+#else
+		m_free(pData, m);			/* release old mbuf */
+#endif
+		mprev = mfirst;
+	}
+	return (m0);
+}
Index: trunk/src/VBox/Devices/Network/slirp/bsd/kern/uipc_mbuf2.c
===================================================================
--- trunk/src/VBox/Devices/Network/slirp/bsd/kern/uipc_mbuf2.c	(revision 27869)
+++ trunk/src/VBox/Devices/Network/slirp/bsd/kern/uipc_mbuf2.c	(revision 27869)
@@ -0,0 +1,538 @@
+/*	$KAME: uipc_mbuf2.c,v 1.31 2001/11/28 11:08:53 itojun Exp $	*/
+/*	$NetBSD: uipc_mbuf.c,v 1.40 1999/04/01 00:23:25 thorpej Exp $	*/
+
+/*-
+ * Copyright (C) 1999 WIDE Project.
+ * 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
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the project 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 PROJECT 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 PROJECT 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.
+ */
+/*-
+ * 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
+ *    documentation and/or other materials provided with the distribution.
+ * 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.4 (Berkeley) 2/14/95
+ */
+#ifndef VBOX
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD: src/sys/kern/uipc_mbuf2.c,v 1.33.8.1 2009/04/15 03:14:26 kensmith Exp $");
+
+/*#define PULLDOWN_DEBUG*/
+
+#include "opt_mac.h"
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/lock.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/mutex.h>
+
+#include <security/mac/mac_framework.h>
+
+static MALLOC_DEFINE(M_PACKET_TAGS, MBUF_TAG_MEM_NAME,
+    "packet-attached information");
+#else
+# include "slirp.h"
+#endif
+
+/* can't call it m_dup(), as freebsd[34] uses m_dup() with different arg */
+#ifndef VBOX
+static struct mbuf *m_dup1(struct mbuf *, int, int, int);
+#else
+static struct mbuf *m_dup1(PNATState, struct mbuf *, int, int, int);
+#endif
+
+/*
+ * ensure that [off, off + len) is contiguous on the mbuf chain "m".
+ * packet chain before "off" is kept untouched.
+ * if offp == NULL, the target will start at <retval, 0> on resulting chain.
+ * if offp != NULL, the target will start at <retval, *offp> on resulting chain.
+ *
+ * on error return (NULL return value), original "m" will be freed.
+ *
+ * XXX: M_TRAILINGSPACE/M_LEADINGSPACE only permitted on writable ext_buf.
+ */
+struct mbuf *
+#ifndef VBOX
+m_pulldown(struct mbuf *m, int off, int len, int *offp)
+#else
+m_pulldown(PNATState pData, struct mbuf *m, int off, int len, int *offp)
+#endif
+{
+	struct mbuf *n, *o;
+	int hlen, tlen, olen;
+	int writable;
+
+	/* check invalid arguments. */
+	if (m == NULL)
+		panic("m == NULL in m_pulldown()");
+	if (len > MCLBYTES) {
+#ifndef VBOX
+		m_freem(m);
+#else
+		m_freem(pData, m);
+#endif
+		return NULL;	/* impossible */
+	}
+
+#ifdef PULLDOWN_DEBUG
+    {
+	struct mbuf *t;
+	printf("before:");
+	for (t = m; t; t = t->m_next)
+		printf(" %d", t->m_len);
+	printf("\n");
+    }
+#endif
+	n = m;
+	while (n != NULL && off > 0) {
+		if (n->m_len > off)
+			break;
+		off -= n->m_len;
+		n = n->m_next;
+	}
+	/* be sure to point non-empty mbuf */
+	while (n != NULL && n->m_len == 0)
+		n = n->m_next;
+	if (!n) {
+#ifndef VBOX
+		m_freem(m);
+#else
+		m_freem(pData, m);
+#endif
+		return NULL;	/* mbuf chain too short */
+	}
+
+	/*
+	 * XXX: This code is flawed because it considers a "writable" mbuf
+	 *      data region to require all of the following:
+	 *	  (i) mbuf _has_ to have M_EXT set; if it is just a regular
+	 *	      mbuf, it is still not considered "writable."
+	 *	  (ii) since mbuf has M_EXT, the ext_type _has_ to be
+	 *	       EXT_CLUSTER. Anything else makes it non-writable.
+	 *	  (iii) M_WRITABLE() must evaluate true.
+	 *      Ideally, the requirement should only be (iii).
+	 *
+	 * If we're writable, we're sure we're writable, because the ref. count
+	 * cannot increase from 1, as that would require posession of mbuf
+	 * n by someone else (which is impossible). However, if we're _not_
+	 * writable, we may eventually become writable )if the ref. count drops
+	 * to 1), but we'll fail to notice it unless we re-evaluate
+	 * M_WRITABLE(). For now, we only evaluate once at the beginning and
+	 * live with this.
+	 */
+	/*
+	 * XXX: This is dumb. If we're just a regular mbuf with no M_EXT,
+	 *      then we're not "writable," according to this code.
+	 */
+	writable = 0;
+	if ((n->m_flags & M_EXT) == 0 ||
+	    (n->m_ext.ext_type == EXT_CLUSTER && M_WRITABLE(n)))
+		writable = 1;
+
+	/*
+	 * the target data is on <n, off>.
+	 * if we got enough data on the mbuf "n", we're done.
+	 */
+	if ((off == 0 || offp) && len <= n->m_len - off && writable)
+		goto ok;
+
+	/*
+	 * when len <= n->m_len - off and off != 0, it is a special case.
+	 * len bytes from <n, off> sits in single mbuf, but the caller does
+	 * not like the starting position (off).
+	 * chop the current mbuf into two pieces, set off to 0.
+	 */
+	if (len <= n->m_len - off) {
+#ifndef VBOX
+		o = m_dup1(n, off, n->m_len - off, M_DONTWAIT);
+#else
+		o = m_dup1(pData, n, off, n->m_len - off, M_DONTWAIT);
+#endif
+		if (o == NULL) {
+#ifndef VBOX
+			m_freem(m);
+#else
+			m_freem(pData, m);
+#endif
+			return NULL;	/* ENOBUFS */
+		}
+		n->m_len = off;
+		o->m_next = n->m_next;
+		n->m_next = o;
+		n = n->m_next;
+		off = 0;
+		goto ok;
+	}
+
+	/*
+	 * we need to take hlen from <n, off> and tlen from <n->m_next, 0>,
+	 * and construct contiguous mbuf with m_len == len.
+	 * note that hlen + tlen == len, and tlen > 0.
+	 */
+	hlen = n->m_len - off;
+	tlen = len - hlen;
+
+	/*
+	 * ensure that we have enough trailing data on mbuf chain.
+	 * if not, we can do nothing about the chain.
+	 */
+	olen = 0;
+	for (o = n->m_next; o != NULL; o = o->m_next)
+		olen += o->m_len;
+	if (hlen + olen < len) {
+#ifndef VBOX
+		m_freem(m);
+#else
+		m_freem(pData, m);
+#endif
+		return NULL;	/* mbuf chain too short */
+	}
+
+	/*
+	 * easy cases first.
+	 * we need to use m_copydata() to get data from <n->m_next, 0>.
+	 */
+	if ((off == 0 || offp) && M_TRAILINGSPACE(n) >= tlen
+	 && writable) {
+		m_copydata(n->m_next, 0, tlen, mtod(n, caddr_t) + n->m_len);
+		n->m_len += tlen;
+#ifndef VBOX
+		m_adj(n->m_next, tlen);
+#else
+		m_adj(pData, n->m_next, tlen);
+#endif
+		goto ok;
+	}
+	if ((off == 0 || offp) && M_LEADINGSPACE(n->m_next) >= hlen
+	 && writable) {
+		n->m_next->m_data -= hlen;
+		n->m_next->m_len += hlen;
+		bcopy(mtod(n, caddr_t) + off, mtod(n->m_next, caddr_t), hlen);
+		n->m_len -= hlen;
+		n = n->m_next;
+		off = 0;
+		goto ok;
+	}
+
+	/*
+	 * now, we need to do the hard way.  don't m_copy as there's no room
+	 * on both end.
+	 */
+	if (len > MLEN)
+#ifndef VBOX
+		o = m_getcl(M_DONTWAIT, m->m_type, 0);
+#else
+		o = m_getcl(pData, M_DONTWAIT, m->m_type, 0);
+#endif
+	else
+#ifndef VBOX
+		o = m_get(M_DONTWAIT, m->m_type);
+#else
+		o = m_get(pData, M_DONTWAIT, m->m_type);
+#endif
+	if (!o) {
+#ifndef VBOX
+		m_freem(m);
+#else
+		m_freem(pData, m);
+#endif
+		return NULL;	/* ENOBUFS */
+	}
+	/* get hlen from <n, off> into <o, 0> */
+	o->m_len = hlen;
+	bcopy(mtod(n, caddr_t) + off, mtod(o, caddr_t), hlen);
+	n->m_len -= hlen;
+	/* get tlen from <n->m_next, 0> into <o, hlen> */
+	m_copydata(n->m_next, 0, tlen, mtod(o, caddr_t) + o->m_len);
+	o->m_len += tlen;
+#ifndef VBOX
+	m_adj(n->m_next, tlen);
+#else
+	m_adj(pData, n->m_next, tlen);
+#endif
+	o->m_next = n->m_next;
+	n->m_next = o;
+	n = o;
+	off = 0;
+
+ok:
+#ifdef PULLDOWN_DEBUG
+    {
+	struct mbuf *t;
+	printf("after:");
+	for (t = m; t; t = t->m_next)
+		printf("%c%d", t == n ? '*' : ' ', t->m_len);
+	printf(" (off=%d)\n", off);
+    }
+#endif
+	if (offp)
+		*offp = off;
+	return n;
+}
+
+static struct mbuf *
+#ifndef VBOX
+m_dup1(struct mbuf *m, int off, int len, int wait)
+#else
+m_dup1(PNATState pData, struct mbuf *m, int off, int len, int wait)
+#endif
+{
+	struct mbuf *n;
+	int copyhdr;
+
+	if (len > MCLBYTES)
+		return NULL;
+	if (off == 0 && (m->m_flags & M_PKTHDR) != 0)
+		copyhdr = 1;
+	else
+		copyhdr = 0;
+	if (len >= MINCLSIZE) {
+		if (copyhdr == 1)
+#ifndef VBOX
+			n = m_getcl(wait, m->m_type, M_PKTHDR);
+#else
+			n = m_getcl(pData, wait, m->m_type, M_PKTHDR);
+#endif
+		else
+#ifndef VBOX
+			n = m_getcl(wait, m->m_type, 0);
+#else
+			n = m_getcl(pData, wait, m->m_type, 0);
+#endif
+	} else {
+		if (copyhdr == 1)
+#ifndef VBOX
+			n = m_gethdr(wait, m->m_type);
+#else
+			n = m_gethdr(pData, wait, m->m_type);
+#endif
+		else
+#ifndef VBOX
+			n = m_get(wait, m->m_type);
+#else
+			n = m_get(pData, wait, m->m_type);
+#endif
+	}
+	if (!n)
+		return NULL; /* ENOBUFS */
+
+	if (copyhdr && !m_dup_pkthdr(n, m, wait)) {
+#ifndef VBOX
+		m_free(n);
+#else
+		m_free(pData, n);
+#endif
+		return NULL;
+	}
+	m_copydata(m, off, len, mtod(n, caddr_t));
+	n->m_len = len;
+	return n;
+}
+
+/* Free a packet tag. */
+void
+m_tag_free_default(struct m_tag *t)
+{
+#ifdef MAC
+	if (t->m_tag_id == PACKET_TAG_MACLABEL)
+		mac_destroy_mbuf_tag(t);
+#endif
+#ifndef VBOX
+	free(t, M_PACKET_TAGS);
+#else
+	RTMemFree(t);
+#endif
+}
+
+/* Get a packet tag structure along with specified data following. */
+struct m_tag *
+m_tag_alloc(u_int32_t cookie, int type, int len, int wait)
+{
+	struct m_tag *t;
+
+	MBUF_CHECKSLEEP(wait);
+	if (len < 0)
+		return NULL;
+#ifndef VBOX
+	t = malloc(len + sizeof(struct m_tag), M_PACKET_TAGS, wait);
+#else
+	t = RTMemAllocZ(len + sizeof(struct m_tag));
+#endif
+	if (t == NULL)
+		return NULL;
+	m_tag_setup(t, cookie, type, len);
+	t->m_tag_free = m_tag_free_default;
+	return t;
+}
+
+/* Unlink and free a packet tag. */
+void
+m_tag_delete(struct mbuf *m, struct m_tag *t)
+{
+
+	KASSERT(m && t, ("m_tag_delete: null argument, m %p t %p", m, t));
+	m_tag_unlink(m, t);
+	m_tag_free(t);
+}
+
+/* Unlink and free a packet tag chain, starting from given tag. */
+void
+m_tag_delete_chain(struct mbuf *m, struct m_tag *t)
+{
+	struct m_tag *p, *q;
+
+	KASSERT(m, ("m_tag_delete_chain: null mbuf"));
+	if (t != NULL)
+		p = t;
+	else
+		p = SLIST_FIRST(&m->m_pkthdr.tags);
+	if (p == NULL)
+		return;
+	while ((q = SLIST_NEXT(p, m_tag_link)) != NULL)
+		m_tag_delete(m, q);
+	m_tag_delete(m, p);
+}
+
+/*
+ * Strip off all tags that would normally vanish when
+ * passing through a network interface.  Only persistent
+ * tags will exist after this; these are expected to remain
+ * so long as the mbuf chain exists, regardless of the
+ * path the mbufs take.
+ */
+void
+m_tag_delete_nonpersistent(struct mbuf *m)
+{
+	struct m_tag *p, *q;
+
+	SLIST_FOREACH_SAFE(p, &m->m_pkthdr.tags, m_tag_link, q)
+		if ((p->m_tag_id & MTAG_PERSISTENT) == 0)
+			m_tag_delete(m, p);
+}
+
+/* Find a tag, starting from a given position. */
+struct m_tag *
+m_tag_locate(struct mbuf *m, u_int32_t cookie, int type, struct m_tag *t)
+{
+	struct m_tag *p;
+
+	KASSERT(m, ("m_tag_locate: null mbuf"));
+	if (t == NULL)
+		p = SLIST_FIRST(&m->m_pkthdr.tags);
+	else
+		p = SLIST_NEXT(t, m_tag_link);
+	while (p != NULL) {
+		if (p->m_tag_cookie == cookie && p->m_tag_id == type)
+			return p;
+		p = SLIST_NEXT(p, m_tag_link);
+	}
+	return NULL;
+}
+
+/* Copy a single tag. */
+struct m_tag *
+m_tag_copy(struct m_tag *t, int how)
+{
+	struct m_tag *p;
+
+	MBUF_CHECKSLEEP(how);
+	KASSERT(t, ("m_tag_copy: null tag"));
+	p = m_tag_alloc(t->m_tag_cookie, t->m_tag_id, t->m_tag_len, how);
+	if (p == NULL)
+		return (NULL);
+#ifdef MAC
+	/*
+	 * XXXMAC: we should probably pass off the initialization, and
+	 * copying here?  can we hide that PACKET_TAG_MACLABEL is
+	 * special from the mbuf code?
+	 */
+	if (t->m_tag_id == PACKET_TAG_MACLABEL) {
+		if (mac_init_mbuf_tag(p, how) != 0) {
+			m_tag_free(p);
+			return (NULL);
+		}
+		mac_copy_mbuf_tag(t, p);
+	} else
+#endif
+		bcopy(t + 1, p + 1, t->m_tag_len); /* Copy the data */
+	return p;
+}
+
+/*
+ * Copy two tag chains. The destination mbuf (to) loses any attached
+ * tags even if the operation fails. This should not be a problem, as
+ * m_tag_copy_chain() is typically called with a newly-allocated
+ * destination mbuf.
+ */
+int
+m_tag_copy_chain(struct mbuf *to, struct mbuf *from, int how)
+{
+	struct m_tag *p, *t, *tprev = NULL;
+
+	MBUF_CHECKSLEEP(how);
+	KASSERT(to && from,
+		("m_tag_copy_chain: null argument, to %p from %p", to, from));
+	m_tag_delete_chain(to, NULL);
+	SLIST_FOREACH(p, &from->m_pkthdr.tags, m_tag_link) {
+		t = m_tag_copy(p, how);
+		if (t == NULL) {
+			m_tag_delete_chain(to, NULL);
+			return 0;
+		}
+		if (tprev == NULL)
+			SLIST_INSERT_HEAD(&to->m_pkthdr.tags, t, m_tag_link);
+		else
+			SLIST_INSERT_AFTER(tprev, t, m_tag_link);
+		tprev = t;
+	}
+	return 1;
+}
Index: trunk/src/VBox/Devices/Network/slirp/bsd/sys/mbuf.h
===================================================================
--- trunk/src/VBox/Devices/Network/slirp/bsd/sys/mbuf.h	(revision 27869)
+++ trunk/src/VBox/Devices/Network/slirp/bsd/sys/mbuf.h	(revision 27869)
@@ -0,0 +1,1167 @@
+/*-
+ * Copyright (c) 1982, 1986, 1988, 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
+ *    documentation and/or other materials provided with the distribution.
+ * 3. 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.
+ *
+ *	@(#)mbuf.h	8.5 (Berkeley) 2/19/95
+ * $FreeBSD: src/sys/sys/mbuf.h,v 1.217.2.3.4.1 2009/04/15 03:14:26 kensmith Exp $
+ */
+
+#ifndef _SYS_MBUF_H_
+#define	_SYS_MBUF_H_
+
+#ifndef VBOX
+/* XXX: These includes suck. Sorry! */
+#include <sys/queue.h>
+#ifdef _KERNEL
+#include <sys/systm.h>
+#include <vm/uma.h>
+#ifdef WITNESS
+#include <sys/lock.h>
+#endif
+#endif
+#else /* VBOX */
+# include <iprt/param.h>
+# include "misc.h"
+# include "ext.h"
+
+typedef const char *c_caddr_t;
+
+static void panic (char *fmt, ...)
+{
+    va_list args;
+    va_start(args, fmt);
+    vbox_slirp_printV(fmt, args);
+    va_end(args);
+    AssertReleaseFailed();
+}
+/* for non-gnu compilers */
+# define __func__ __FUNCTION__
+# ifndef __inline
+#  define __inline
+# endif
+
+# define bzero(a1, len) memset((a1), 0, (len))
+
+/* (vvl) some definitions from sys/param.h */
+/*
+ * Constants related to network buffer management.
+ * MCLBYTES must be no larger than PAGE_SIZE.
+ */
+# ifndef	MSIZE
+#  define MSIZE		256		/* size of an mbuf */
+# endif	/* MSIZE */
+
+# ifndef	MCLSHIFT
+#  define MCLSHIFT	11		/* convert bytes to mbuf clusters */
+# endif	/* MCLSHIFT */
+
+# ifndef MCLBYTES
+#  define MCLBYTES	(1 << MCLSHIFT)	/* size of an mbuf cluster */
+# endif /*MCLBYTES*/
+
+# define	MJUMPAGESIZE	PAGE_SIZE	/* jumbo cluster 4k */
+# define	MJUM9BYTES	(9 * 1024)	/* jumbo cluster 9k */
+# define	MJUM16BYTES	(16 * 1024)	/* jumbo cluster 16k */
+#endif /* VBOX */
+
+/*
+ * Mbufs are of a single size, MSIZE (sys/param.h), which includes overhead.
+ * An mbuf may add a single "mbuf cluster" of size MCLBYTES (also in
+ * sys/param.h), which has no additional overhead and is used instead of the
+ * internal data area; this is done when at least MINCLSIZE of data must be
+ * stored.  Additionally, it is possible to allocate a separate buffer
+ * externally and attach it to the mbuf in a way similar to that of mbuf
+ * clusters.
+ */
+#define	MLEN		(MSIZE - sizeof(struct m_hdr))	/* normal data len */
+#define	MHLEN		(MLEN - sizeof(struct pkthdr))	/* data len w/pkthdr */
+#define	MINCLSIZE	(MHLEN + 1)	/* smallest amount to put in cluster */
+#define	M_MAXCOMPRESS	(MHLEN / 2)	/* max amount to copy for compression */
+
+#if defined(_KERNEL) || defined(VBOX)
+/*-
+ * Macros for type conversion:
+ * mtod(m, t)	-- Convert mbuf pointer to data pointer of correct type.
+ * dtom(x)	-- Convert data pointer within mbuf to mbuf pointer (XXX).
+ */
+#define	mtod(m, t)	((t)((m)->m_data))
+#define	dtom(x)		((struct mbuf *)((intptr_t)(x) & ~(MSIZE-1)))
+
+/*
+ * Argument structure passed to UMA routines during mbuf and packet
+ * allocations.
+ */
+struct mb_args {
+	int	flags;	/* Flags for mbuf being allocated */
+	short	type;	/* Type of mbuf being allocated */
+};
+#endif /* _KERNEL */
+
+#if defined(__LP64__)
+#define M_HDR_PAD    6
+#else
+#define M_HDR_PAD    2
+#endif
+
+/*
+ * Header present at the beginning of every mbuf.
+ */
+struct m_hdr {
+	struct mbuf	*mh_next;	/* next buffer in chain */
+	struct mbuf	*mh_nextpkt;	/* next chain in queue/record */
+	caddr_t		 mh_data;	/* location of data */
+	int		 mh_len;	/* amount of data in this mbuf */
+	int		 mh_flags;	/* flags; see below */
+	short		 mh_type;	/* type of data in this mbuf */
+#ifdef VBOX
+        struct socket   *mh_so;         /*socket assotiated with mbuf*/
+        TAILQ_ENTRY(mbuf) mh_ifq;
+#endif
+	uint8_t          pad[M_HDR_PAD];/* word align                  */
+};
+
+/*
+ * Packet tag structure (see below for details).
+ */
+struct m_tag {
+	SLIST_ENTRY(m_tag)	m_tag_link;	/* List of packet tags */
+	u_int16_t		m_tag_id;	/* Tag ID */
+	u_int16_t		m_tag_len;	/* Length of data */
+	u_int32_t		m_tag_cookie;	/* ABI/Module ID */
+	void			(*m_tag_free)(struct m_tag *);
+};
+
+/*
+ * Record/packet header in first mbuf of chain; valid only if M_PKTHDR is set.
+ */
+struct pkthdr {
+	struct ifnet	*rcvif;		/* rcv interface */
+	/* variables for ip and tcp reassembly */
+	void		*header;	/* pointer to packet header */
+	int		 len;		/* total packet length */
+	/* variables for hardware checksum */
+	int		 csum_flags;	/* flags regarding checksum */
+	int		 csum_data;	/* data field used by csum routines */
+	u_int16_t	 tso_segsz;	/* TSO segment size */
+	u_int16_t	 ether_vtag;	/* Ethernet 802.1p+q vlan tag */
+	SLIST_HEAD(packet_tags, m_tag) tags; /* list of packet tags */
+};
+
+/*
+ * Description of external storage mapped into mbuf; valid only if M_EXT is
+ * set.
+ */
+struct m_ext {
+	caddr_t		 ext_buf;	/* start of buffer */
+	void		(*ext_free)	/* free routine if not the usual */
+			    (void *, void *);
+	void		*ext_args;	/* optional argument pointer */
+	u_int		 ext_size;	/* size of buffer, for ext_free */
+#ifdef VBOX
+	volatile uint32_t *ref_cnt;	/* pointer to ref count info */
+#else
+	volatile u_int	*ref_cnt;	/* pointer to ref count info */
+#endif
+	int		 ext_type;	/* type of external storage */
+};
+
+/*
+ * The core of the mbuf object along with some shortcut defines for practical
+ * purposes.
+ */
+struct mbuf {
+	struct m_hdr	m_hdr;
+	union {
+		struct {
+			struct pkthdr	MH_pkthdr;	/* M_PKTHDR set */
+			union {
+				struct m_ext	MH_ext;	/* M_EXT set */
+				char		MH_databuf[MHLEN];
+			} MH_dat;
+		} MH;
+		char	M_databuf[MLEN];		/* !M_PKTHDR, !M_EXT */
+	} M_dat;
+};
+#define	m_next		m_hdr.mh_next
+#define	m_len		m_hdr.mh_len
+#define	m_data		m_hdr.mh_data
+#define	m_type		m_hdr.mh_type
+#define	m_flags		m_hdr.mh_flags
+#define	m_nextpkt	m_hdr.mh_nextpkt
+#define	m_act		m_nextpkt
+#define	m_pkthdr	M_dat.MH.MH_pkthdr
+#define	m_ext		M_dat.MH.MH_dat.MH_ext
+#define	m_pktdat	M_dat.MH.MH_dat.MH_databuf
+#define	m_dat		M_dat.M_databuf
+#ifdef VBOX
+# define m_so           m_hdr.mh_so
+# define ifq_so         m_hdr.mh_so
+# define m_ifq          m_hdr.mh_ifq
+#endif
+
+/*
+ * mbuf flags.
+ */
+#define	M_EXT		0x00000001 /* has associated external storage */
+#define	M_PKTHDR	0x00000002 /* start of record */
+#define	M_EOR		0x00000004 /* end of record */
+#define	M_RDONLY	0x00000008 /* associated data is marked read-only */
+#define	M_PROTO1	0x00000010 /* protocol-specific */
+#define	M_PROTO2	0x00000020 /* protocol-specific */
+#define	M_PROTO3	0x00000040 /* protocol-specific */
+#define	M_PROTO4	0x00000080 /* protocol-specific */
+#define	M_PROTO5	0x00000100 /* protocol-specific */
+#define	M_BCAST		0x00000200 /* send/received as link-level broadcast */
+#define	M_MCAST		0x00000400 /* send/received as link-level multicast */
+#define	M_FRAG		0x00000800 /* packet is a fragment of a larger packet */
+#define	M_FIRSTFRAG	0x00001000 /* packet is first fragment */
+#define	M_LASTFRAG	0x00002000 /* packet is last fragment */
+#define	M_SKIP_FIREWALL	0x00004000 /* skip firewall processing */
+#define	M_FREELIST	0x00008000 /* mbuf is on the free list */
+#define	M_VLANTAG	0x00010000 /* ether_vtag is valid */
+#define	M_PROMISC	0x00020000 /* packet was not for us */
+#define	M_NOFREE	0x00040000 /* do not free mbuf, embedded in cluster */
+#define	M_PROTO6	0x00080000 /* protocol-specific */
+#define	M_PROTO7	0x00100000 /* protocol-specific */
+#define	M_PROTO8	0x00200000 /* protocol-specific */
+/*
+ * For RELENG_{6,7} steal these flags for limited multiple routing table
+ * support. In RELENG_8 and beyond, use just one flag and a tag.
+ */
+#define	M_FIB		0xF0000000 /* steal some bits to store fib number. */
+
+#define	M_NOTIFICATION	M_PROTO5    /* SCTP notification */
+
+/*
+ * Flags to purge when crossing layers.
+ */
+#define	M_PROTOFLAGS \
+    (M_PROTO1|M_PROTO2|M_PROTO3|M_PROTO4|M_PROTO5|M_PROTO6|M_PROTO7|M_PROTO8)
+
+/*
+ * Flags preserved when copying m_pkthdr.
+ */
+#define	M_COPYFLAGS \
+    (M_PKTHDR|M_EOR|M_RDONLY|M_PROTOFLAGS|M_SKIP_FIREWALL|M_BCAST|M_MCAST|\
+     M_FRAG|M_FIRSTFRAG|M_LASTFRAG|M_VLANTAG|M_PROMISC|M_FIB)
+
+/*
+ * External buffer types: identify ext_buf type.
+ */
+#define	EXT_CLUSTER	1	/* mbuf cluster */
+#define	EXT_SFBUF	2	/* sendfile(2)'s sf_bufs */
+#define	EXT_JUMBOP	3	/* jumbo cluster 4096 bytes */
+#define	EXT_JUMBO9	4	/* jumbo cluster 9216 bytes */
+#define	EXT_JUMBO16	5	/* jumbo cluster 16184 bytes */
+#define	EXT_PACKET	6	/* mbuf+cluster from packet zone */
+#define	EXT_MBUF	7	/* external mbuf reference (M_IOVEC) */
+#define	EXT_NET_DRV	100	/* custom ext_buf provided by net driver(s) */
+#define	EXT_MOD_TYPE	200	/* custom module's ext_buf type */
+#define	EXT_DISPOSABLE	300	/* can throw this buffer away w/page flipping */
+#define	EXT_EXTREF	400	/* has externally maintained ref_cnt ptr */
+
+/*
+ * Flags indicating hw checksum support and sw checksum requirements.  This
+ * field can be directly tested against if_data.ifi_hwassist.
+ */
+#define	CSUM_IP			0x0001		/* will csum IP */
+#define	CSUM_TCP		0x0002		/* will csum TCP */
+#define	CSUM_UDP		0x0004		/* will csum UDP */
+#define	CSUM_IP_FRAGS		0x0008		/* will csum IP fragments */
+#define	CSUM_FRAGMENT		0x0010		/* will do IP fragmentation */
+#define	CSUM_TSO		0x0020		/* will do TSO */
+
+#define	CSUM_IP_CHECKED		0x0100		/* did csum IP */
+#define	CSUM_IP_VALID		0x0200		/*   ... the csum is valid */
+#define	CSUM_DATA_VALID		0x0400		/* csum_data field is valid */
+#define	CSUM_PSEUDO_HDR		0x0800		/* csum_data has pseudo hdr */
+
+#define	CSUM_DELAY_DATA		(CSUM_TCP | CSUM_UDP)
+#define	CSUM_DELAY_IP		(CSUM_IP)	/* XXX add ipv6 here too? */
+
+/*
+ * mbuf types.
+ */
+#define	MT_NOTMBUF	0	/* USED INTERNALLY ONLY! Object is not mbuf */
+#define	MT_DATA		1	/* dynamic (data) allocation */
+#define	MT_HEADER	MT_DATA	/* packet header, use M_PKTHDR instead */
+#define	MT_SONAME	8	/* socket name */
+#define	MT_CONTROL	14	/* extra-data protocol message */
+#define	MT_OOBDATA	15	/* expedited data  */
+#define	MT_NTYPES	16	/* number of mbuf types for mbtypes[] */
+
+#define	MT_NOINIT	255	/* Not a type but a flag to allocate
+				   a non-initialized mbuf */
+
+#define MB_NOTAGS	0x1UL	/* no tags attached to mbuf */
+
+/*
+ * General mbuf allocator statistics structure.
+ *
+ * Many of these statistics are no longer used; we instead track many
+ * allocator statistics through UMA's built in statistics mechanism.
+ */
+struct mbstat {
+	u_long	m_mbufs;	/* XXX */
+	u_long	m_mclusts;	/* XXX */
+
+	u_long	m_drain;	/* times drained protocols for space */
+	u_long	m_mcfail;	/* XXX: times m_copym failed */
+	u_long	m_mpfail;	/* XXX: times m_pullup failed */
+	u_long	m_msize;	/* length of an mbuf */
+	u_long	m_mclbytes;	/* length of an mbuf cluster */
+	u_long	m_minclsize;	/* min length of data to allocate a cluster */
+	u_long	m_mlen;		/* length of data in an mbuf */
+	u_long	m_mhlen;	/* length of data in a header mbuf */
+
+	/* Number of mbtypes (gives # elems in mbtypes[] array) */
+	short	m_numtypes;
+
+	/* XXX: Sendfile stats should eventually move to their own struct */
+	u_long	sf_iocnt;	/* times sendfile had to do disk I/O */
+	u_long	sf_allocfail;	/* times sfbuf allocation failed */
+	u_long	sf_allocwait;	/* times sfbuf allocation had to wait */
+};
+
+/*
+ * Flags specifying how an allocation should be made.
+ *
+ * The flag to use is as follows:
+ * - M_DONTWAIT or M_NOWAIT from an interrupt handler to not block allocation.
+ * - M_WAIT or M_WAITOK or M_TRYWAIT from wherever it is safe to block.
+ *
+ * M_DONTWAIT/M_NOWAIT means that we will not block the thread explicitly and
+ * if we cannot allocate immediately we may return NULL, whereas
+ * M_WAIT/M_WAITOK/M_TRYWAIT means that if we cannot allocate resources we
+ * will block until they are available, and thus never return NULL.
+ *
+ * XXX Eventually just phase this out to use M_WAITOK/M_NOWAIT.
+ */
+#define	MBTOM(how)	(how)
+#ifndef VBOX
+#define	M_DONTWAIT	M_NOWAIT
+#define	M_TRYWAIT	M_WAITOK
+#define	M_WAIT		M_WAITOK
+#else
+/* @todo (r=vvl) not sure we can do it in NAT */
+# define M_WAITOK  0
+# define M_NOWAIT  0
+# define M_DONTWAIT  0
+# define M_TRYWAI    0
+# define M_WAIT	    0
+#endif
+
+/*
+ * String names of mbuf-related UMA(9) and malloc(9) types.  Exposed to
+ * !_KERNEL so that monitoring tools can look up the zones with
+ * libmemstat(3).
+ */
+#define	MBUF_MEM_NAME		"mbuf"
+#define	MBUF_CLUSTER_MEM_NAME	"mbuf_cluster"
+#define	MBUF_PACKET_MEM_NAME	"mbuf_packet"
+#define	MBUF_JUMBOP_MEM_NAME	"mbuf_jumbo_pagesize"
+#define	MBUF_JUMBO9_MEM_NAME	"mbuf_jumbo_9k"
+#define	MBUF_JUMBO16_MEM_NAME	"mbuf_jumbo_16k"
+#define	MBUF_TAG_MEM_NAME	"mbuf_tag"
+#define	MBUF_EXTREFCNT_MEM_NAME	"mbuf_ext_refcnt"
+
+#if defined(_KERNEL) || defined(VBOX)
+
+#ifdef WITNESS
+#define	MBUF_CHECKSLEEP(how) do {					\
+	if (how == M_WAITOK)						\
+		WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,		\
+		    "Sleeping in \"%s\"", __func__);			\
+} while (0)
+#else
+#define	MBUF_CHECKSLEEP(how)
+#endif
+
+/*
+ * Network buffer allocation API
+ *
+ * The rest of it is defined in kern/kern_mbuf.c
+ */
+
+#ifndef VBOX
+extern uma_zone_t	zone_mbuf;
+extern uma_zone_t	zone_clust;
+extern uma_zone_t	zone_pack;
+extern uma_zone_t	zone_jumbop;
+extern uma_zone_t	zone_jumbo9;
+extern uma_zone_t	zone_jumbo16;
+extern uma_zone_t	zone_ext_refcnt;
+#endif
+
+#ifndef VBOX
+static __inline struct mbuf	*m_getcl(int how, short type, int flags);
+static __inline struct mbuf	*m_get(int how, short type);
+static __inline struct mbuf	*m_gethdr(int how, short type);
+static __inline struct mbuf	*m_getjcl(int how, short type, int flags,
+				    int size);
+static __inline struct mbuf	*m_getclr(int how, short type);	/* XXX */
+static __inline struct mbuf	*m_free(struct mbuf *m);
+static __inline void		 m_clget(struct mbuf *m, int how);
+static __inline void		*m_cljget(struct mbuf *m, int how, int size);
+void				 mb_free_ext(struct mbuf *);
+#else
+static __inline struct mbuf	*m_getcl(PNATState pData, int how, short type, int flags);
+static __inline struct mbuf	*m_get(PNATState pData, int how, short type);
+static __inline struct mbuf	*m_gethdr(PNATState pData, int how, short type);
+static __inline struct mbuf	*m_getjcl(PNATState pData, int how,
+                                    short type, int flags, int size);
+static __inline struct mbuf	*m_getclr(PNATState pData, int how, short type);	/* XXX */
+static __inline struct mbuf	*m_free(PNATState pData, struct mbuf *m);
+static __inline void		 m_clget(PNATState pData, struct mbuf *m, int how);
+static __inline void		*m_cljget(PNATState pData, struct mbuf *m, int how, int size);
+void				 mb_free_ext(PNATState, struct mbuf *);
+#endif
+static __inline void		 m_chtype(struct mbuf *m, short new_type);
+static __inline struct mbuf	*m_last(struct mbuf *m);
+
+static __inline int
+m_gettype(int size)
+{
+	int type;
+
+	switch (size) {
+	case MSIZE:
+		type = EXT_MBUF;
+		break;
+	case MCLBYTES:
+		type = EXT_CLUSTER;
+		break;
+#if MJUMPAGESIZE != MCLBYTES
+	case MJUMPAGESIZE:
+		type = EXT_JUMBOP;
+		break;
+#endif
+	case MJUM9BYTES:
+		type = EXT_JUMBO9;
+		break;
+	case MJUM16BYTES:
+		type = EXT_JUMBO16;
+		break;
+	default:
+		panic("%s: m_getjcl: invalid cluster size", __func__);
+	}
+
+	return (type);
+}
+
+static __inline uma_zone_t
+#ifndef VBOX
+m_getzone(int size)
+#else
+m_getzone(PNATState pData, int size)
+#endif
+{
+	uma_zone_t zone;
+
+	switch (size) {
+	case MSIZE:
+		zone = zone_mbuf;
+		break;
+	case MCLBYTES:
+		zone = zone_clust;
+		break;
+#if MJUMPAGESIZE != MCLBYTES
+	case MJUMPAGESIZE:
+		zone = zone_jumbop;
+		break;
+#endif
+	case MJUM9BYTES:
+		zone = zone_jumbo9;
+		break;
+	case MJUM16BYTES:
+		zone = zone_jumbo16;
+		break;
+	default:
+		panic("%s: m_getjcl: invalid cluster type", __func__);
+	}
+
+	return (zone);
+}
+
+static __inline struct mbuf *
+#ifndef VBOX
+m_get(int how, short type)
+#else
+m_get(PNATState pData, int how, short type)
+#endif
+{
+	struct mb_args args;
+
+	args.flags = 0;
+	args.type = type;
+	return ((struct mbuf *)(uma_zalloc_arg(zone_mbuf, &args, how)));
+}
+
+/*
+ * XXX This should be deprecated, very little use.
+ */
+static __inline struct mbuf *
+#ifndef VBOX
+m_getclr(int how, short type)
+#else
+m_getclr(PNATState pData, int how, short type)
+#endif
+{
+	struct mbuf *m;
+	struct mb_args args;
+
+	args.flags = 0;
+	args.type = type;
+	m = uma_zalloc_arg(zone_mbuf, &args, how);
+	if (m != NULL)
+		bzero(m->m_data, MLEN);
+	return (m);
+}
+
+static __inline struct mbuf *
+#ifndef VBOX
+m_gethdr(int how, short type)
+#else
+m_gethdr(PNATState pData, int how, short type)
+#endif
+{
+	struct mb_args args;
+
+	args.flags = M_PKTHDR;
+	args.type = type;
+	return ((struct mbuf *)(uma_zalloc_arg(zone_mbuf, &args, how)));
+}
+
+static __inline struct mbuf *
+#ifndef VBOX
+m_getcl(int how, short type, int flags)
+#else
+m_getcl(PNATState pData, int how, short type, int flags)
+#endif
+{
+	struct mb_args args;
+
+	args.flags = flags;
+	args.type = type;
+	return ((struct mbuf *)(uma_zalloc_arg(zone_pack, &args, how)));
+}
+
+/*
+ * m_getjcl() returns an mbuf with a cluster of the specified size attached.
+ * For size it takes MCLBYTES, MJUMPAGESIZE, MJUM9BYTES, MJUM16BYTES.
+ *
+ * XXX: This is rather large, should be real function maybe.
+ */
+static __inline struct mbuf *
+#ifndef VBOX
+m_getjcl(int how, short type, int flags, int size)
+#else
+m_getjcl(PNATState pData, int how, short type, int flags, int size)
+#endif
+{
+	struct mb_args args;
+	struct mbuf *m, *n;
+	uma_zone_t zone;
+
+	args.flags = flags;
+	args.type = type;
+
+	m = uma_zalloc_arg(zone_mbuf, &args, how);
+	if (m == NULL)
+		return (NULL);
+
+#ifndef VBOX
+	zone = m_getzone(size);
+#else
+	zone = m_getzone(pData, size);
+#endif
+	n = uma_zalloc_arg(zone, m, how);
+	if (n == NULL) {
+		uma_zfree(zone_mbuf, m);
+		return (NULL);
+	}
+	return (m);
+}
+
+#ifndef VBOX
+static __inline void
+m_free_fast(struct mbuf *m)
+{
+	KASSERT(SLIST_EMPTY(&m->m_pkthdr.tags), ("doing fast free of mbuf with tags"));
+
+	uma_zfree_arg(zone_mbuf, m, (void *)MB_NOTAGS);
+}
+#else
+static __inline void
+m_free_fast(PNATState pData, struct mbuf *m)
+{
+	AssertMsg(SLIST_EMPTY(&m->m_pkthdr.tags), ("doing fast free of mbuf with tags"));
+
+	uma_zfree_arg(zone_mbuf, m, (void *)MB_NOTAGS);
+}
+#endif
+
+static __inline struct mbuf *
+#ifndef VBOX
+m_free(struct mbuf *m)
+#else
+m_free(PNATState pData, struct mbuf *m)
+#endif
+{
+	struct mbuf *n = m->m_next;
+
+	if (m->m_flags & M_EXT)
+#ifndef VBOX
+		mb_free_ext(m);
+#else
+		mb_free_ext(pData, m);
+#endif
+	else if ((m->m_flags & M_NOFREE) == 0)
+		uma_zfree(zone_mbuf, m);
+	return (n);
+}
+
+static __inline void
+#ifndef VBOX
+m_clget(struct mbuf *m, int how)
+#else
+m_clget(PNATState pData, struct mbuf *m, int how)
+#endif
+{
+
+	if (m->m_flags & M_EXT)
+		printf("%s: %p mbuf already has cluster\n", __func__, m);
+	m->m_ext.ext_buf = (char *)NULL;
+	uma_zalloc_arg(zone_clust, m, how);
+	/*
+	 * On a cluster allocation failure, drain the packet zone and retry,
+	 * we might be able to loosen a few clusters up on the drain.
+	 */
+	if ((how & M_NOWAIT) && (m->m_ext.ext_buf == NULL)) {
+		zone_drain(zone_pack);
+		uma_zalloc_arg(zone_clust, m, how);
+	}
+}
+
+/*
+ * m_cljget() is different from m_clget() as it can allocate clusters without
+ * attaching them to an mbuf.  In that case the return value is the pointer
+ * to the cluster of the requested size.  If an mbuf was specified, it gets
+ * the cluster attached to it and the return value can be safely ignored.
+ * For size it takes MCLBYTES, MJUMPAGESIZE, MJUM9BYTES, MJUM16BYTES.
+ */
+static __inline void *
+#ifndef VBOX
+m_cljget(struct mbuf *m, int how, int size)
+#else
+m_cljget(PNATState pData, struct mbuf *m, int how, int size)
+#endif
+{
+	uma_zone_t zone;
+
+	if (m && m->m_flags & M_EXT)
+		printf("%s: %p mbuf already has cluster\n", __func__, m);
+	if (m != NULL)
+		m->m_ext.ext_buf = NULL;
+
+#ifndef VBOX
+	zone = m_getzone(size);
+#else
+	zone = m_getzone(pData, size);
+#endif
+	return (uma_zalloc_arg(zone, m, how));
+}
+
+static __inline void
+#ifndef VBOX
+m_cljset(struct mbuf *m, void *cl, int type)
+#else
+m_cljset(PNATState pData, struct mbuf *m, void *cl, int type)
+#endif
+{
+	uma_zone_t zone;
+	int size;
+
+	switch (type) {
+	case EXT_CLUSTER:
+		size = MCLBYTES;
+		zone = zone_clust;
+		break;
+#if MJUMPAGESIZE != MCLBYTES
+	case EXT_JUMBOP:
+		size = MJUMPAGESIZE;
+		zone = zone_jumbop;
+		break;
+#endif
+	case EXT_JUMBO9:
+		size = MJUM9BYTES;
+		zone = zone_jumbo9;
+		break;
+	case EXT_JUMBO16:
+		size = MJUM16BYTES;
+		zone = zone_jumbo16;
+		break;
+	default:
+		panic("unknown cluster type");
+		break;
+	}
+
+	m->m_data = m->m_ext.ext_buf = cl;
+#ifdef VBOX
+        m->m_ext.ext_free = (void (*)(void *, void *))0;
+        m->m_ext.ext_args = NULL;
+#else
+	m->m_ext.ext_free = m->m_ext.ext_args = NULL;
+#endif
+	m->m_ext.ext_size = size;
+	m->m_ext.ext_type = type;
+	m->m_ext.ref_cnt = uma_find_refcnt(zone, cl);
+	m->m_flags |= M_EXT;
+
+}
+
+static __inline void
+m_chtype(struct mbuf *m, short new_type)
+{
+
+	m->m_type = new_type;
+}
+
+static __inline struct mbuf *
+m_last(struct mbuf *m)
+{
+
+	while (m->m_next)
+		m = m->m_next;
+	return (m);
+}
+
+/*
+ * mbuf, cluster, and external object allocation macros (for compatibility
+ * purposes).
+ */
+#define	M_MOVE_PKTHDR(to, from)	m_move_pkthdr((to), (from))
+#ifndef VBOX
+#define	MGET(m, how, type)	((m) = m_get((how), (type)))
+#define	MGETHDR(m, how, type)	((m) = m_gethdr((how), (type)))
+#define	MCLGET(m, how)		m_clget((m), (how))
+#define	MEXTADD(m, buf, size, free, args, flags, type) 			\
+    m_extadd((m), (caddr_t)(buf), (size), (free), (args), (flags), (type))
+#define	m_getm(m, len, how, type)					\
+    m_getm2((m), (len), (how), (type), M_PKTHDR)
+#else /*!VBOX*/
+#define	MGET(m, how, type)	((m) = m_get(pData, (how), (type)))
+#define	MGETHDR(m, how, type)	((m) = m_gethdr(pData, (how), (type)))
+#define	MCLGET(m, how)		m_clget(pData, (m), (how))
+#define	MEXTADD(m, buf, size, free, args, flags, type) 			\
+    m_extadd(pData, (m), (caddr_t)(buf), (size), (free), (args), (flags), (type))
+#define	m_getm(m, len, how, type)					\
+    m_getm2(pData, (m), (len), (how), (type), M_PKTHDR)
+#endif
+
+/*
+ * Evaluate TRUE if it's safe to write to the mbuf m's data region (this can
+ * be both the local data payload, or an external buffer area, depending on
+ * whether M_EXT is set).
+ */
+#define	M_WRITABLE(m)	(!((m)->m_flags & M_RDONLY) &&			\
+			 (!(((m)->m_flags & M_EXT)) ||			\
+			 (*((m)->m_ext.ref_cnt) == 1)) )		\
+
+/* Check if the supplied mbuf has a packet header, or else panic. */
+#define	M_ASSERTPKTHDR(m)						\
+	KASSERT(m != NULL && m->m_flags & M_PKTHDR,			\
+	    ("%s: no mbuf packet header!", __func__))
+
+/*
+ * Ensure that the supplied mbuf is a valid, non-free mbuf.
+ *
+ * XXX: Broken at the moment.  Need some UMA magic to make it work again.
+ */
+#define	M_ASSERTVALID(m)						\
+	KASSERT((((struct mbuf *)m)->m_flags & 0) == 0,			\
+	    ("%s: attempted use of a free mbuf!", __func__))
+
+/*
+ * Set the m_data pointer of a newly-allocated mbuf (m_get/MGET) to place an
+ * object of the specified size at the end of the mbuf, longword aligned.
+ */
+#define	M_ALIGN(m, len) do {						\
+	KASSERT(!((m)->m_flags & (M_PKTHDR|M_EXT)),			\
+		("%s: M_ALIGN not normal mbuf", __func__));		\
+	KASSERT((m)->m_data == (m)->m_dat,				\
+		("%s: M_ALIGN not a virgin mbuf", __func__));		\
+	(m)->m_data += (MLEN - (len)) & ~(sizeof(long) - 1);		\
+} while (0)
+
+/*
+ * As above, for mbufs allocated with m_gethdr/MGETHDR or initialized by
+ * M_DUP/MOVE_PKTHDR.
+ */
+#define	MH_ALIGN(m, len) do {						\
+	KASSERT((m)->m_flags & M_PKTHDR && !((m)->m_flags & M_EXT),	\
+		("%s: MH_ALIGN not PKTHDR mbuf", __func__));		\
+	KASSERT((m)->m_data == (m)->m_pktdat,				\
+		("%s: MH_ALIGN not a virgin mbuf", __func__));		\
+	(m)->m_data += (MHLEN - (len)) & ~(sizeof(long) - 1);		\
+} while (0)
+
+/*
+ * Compute the amount of space available before the current start of data in
+ * an mbuf.
+ *
+ * The M_WRITABLE() is a temporary, conservative safety measure: the burden
+ * of checking writability of the mbuf data area rests solely with the caller.
+ */
+#define	M_LEADINGSPACE(m)						\
+	((m)->m_flags & M_EXT ?						\
+	    (M_WRITABLE(m) ? (m)->m_data - (m)->m_ext.ext_buf : 0):	\
+	    (m)->m_flags & M_PKTHDR ? (m)->m_data - (m)->m_pktdat :	\
+	    (m)->m_data - (m)->m_dat)
+
+/*
+ * Compute the amount of space available after the end of data in an mbuf.
+ *
+ * The M_WRITABLE() is a temporary, conservative safety measure: the burden
+ * of checking writability of the mbuf data area rests solely with the caller.
+ */
+#define	M_TRAILINGSPACE(m)						\
+	((m)->m_flags & M_EXT ?						\
+	    (M_WRITABLE(m) ? (m)->m_ext.ext_buf + (m)->m_ext.ext_size	\
+		- ((m)->m_data + (m)->m_len) : 0) :			\
+	    &(m)->m_dat[MLEN] - ((m)->m_data + (m)->m_len))
+
+/*
+ * Arrange to prepend space of size plen to mbuf m.  If a new mbuf must be
+ * allocated, how specifies whether to wait.  If the allocation fails, the
+ * original mbuf chain is freed and m is set to NULL.
+ */
+#define	M_PREPEND(m, plen, how) do {					\
+	struct mbuf **_mmp = &(m);					\
+	struct mbuf *_mm = *_mmp;					\
+	int _mplen = (plen);						\
+	int __mhow = (how);						\
+									\
+	MBUF_CHECKSLEEP(how);						\
+	if (M_LEADINGSPACE(_mm) >= _mplen) {				\
+		_mm->m_data -= _mplen;					\
+		_mm->m_len += _mplen;					\
+	} else								\
+		_mm = m_prepend(_mm, _mplen, __mhow);			\
+	if (_mm != NULL && _mm->m_flags & M_PKTHDR)			\
+		_mm->m_pkthdr.len += _mplen;				\
+	*_mmp = _mm;							\
+} while (0)
+
+/*
+ * Change mbuf to new type.  This is a relatively expensive operation and
+ * should be avoided.
+ */
+#define	MCHTYPE(m, t)	m_chtype((m), (t))
+
+/* Length to m_copy to copy all. */
+#define	M_COPYALL	1000000000
+
+/* Compatibility with 4.3. */
+#define	m_copy(m, o, l)	m_copym((m), (o), (l), M_DONTWAIT)
+
+extern int		max_datalen;	/* MHLEN - max_hdr */
+extern int		max_hdr;	/* Largest link + protocol header */
+extern int		max_linkhdr;	/* Largest link-level header */
+extern int		max_protohdr;	/* Largest protocol header */
+extern struct mbstat	mbstat;		/* General mbuf stats/infos */
+extern int		nmbclusters;	/* Maximum number of clusters */
+
+struct uio;
+
+void		 m_align(struct mbuf *, int);
+int		 m_apply(struct mbuf *, int, int,
+		    int (*)(void *, void *, u_int), void *);
+#ifndef VBOX
+void		 m_adj(struct mbuf *, int);
+int		 m_append(struct mbuf *, int, c_caddr_t);
+struct mbuf	*m_defrag(struct mbuf *, int);
+struct mbuf	*m_dup(struct mbuf *, int);
+void		 m_cat(struct mbuf *, struct mbuf *);
+struct mbuf	*m_collapse(struct mbuf *, int, int);
+void		 m_copyback(struct mbuf *, int, int, c_caddr_t);
+struct mbuf	*m_copym(struct mbuf *, int, int, int);
+struct mbuf	*m_copymdata(struct mbuf *, struct mbuf *,
+		    int, int, int, int);
+struct mbuf	*m_copypacket(struct mbuf *, int);
+struct mbuf	*m_copyup(struct mbuf *n, int len, int dstoff);
+void		 m_extadd(struct mbuf *, caddr_t, u_int,
+		    void (*)(void *, void *), void *, int, int);
+#else
+void		 m_adj(PNATState, struct mbuf *, int);
+int		 m_append(PNATState pData, struct mbuf *, int, c_caddr_t);
+struct mbuf	*m_defrag(PNATState, struct mbuf *, int);
+struct mbuf	*m_dup(PNATState, struct mbuf *, int);
+void		 m_cat(PNATState, struct mbuf *, struct mbuf *);
+struct mbuf	*m_collapse(PNATState, struct mbuf *, int, int);
+void		 m_copyback(PNATState, struct mbuf *, int, int, c_caddr_t);
+struct mbuf	*m_copym(PNATState, struct mbuf *, int, int, int);
+struct mbuf	*m_copymdata(PNATState, struct mbuf *, struct mbuf *,
+		    int, int, int, int);
+struct mbuf	*m_copypacket(PNATState, struct mbuf *, int);
+struct mbuf	*m_copyup(PNATState, struct mbuf *n, int len, int dstoff);
+void		 m_extadd(PNATState pData, struct mbuf *, caddr_t, u_int,
+		    void (*)(void *, void *), void *, int, int);
+#endif
+void		 m_copydata(const struct mbuf *, int, int, caddr_t);
+void		 m_copy_pkthdr(struct mbuf *, struct mbuf *);
+void		 m_demote(struct mbuf *, int);
+struct mbuf	*m_devget(char *, int, int, struct ifnet *,
+		    void (*)(char *, caddr_t, u_int));
+int		 m_dup_pkthdr(struct mbuf *, struct mbuf *, int);
+u_int		 m_fixhdr(struct mbuf *);
+struct mbuf	*m_fragment(struct mbuf *, int, int);
+#ifndef VBOX
+void		 m_freem(struct mbuf *);
+struct mbuf	*m_getm2(struct mbuf *, int, int, short, int);
+struct mbuf	*m_prepend(struct mbuf *, int, int);
+struct mbuf	*m_pulldown(struct mbuf *, int, int, int *);
+struct mbuf	*m_pullup(struct mbuf *, int);
+int		m_sanity(struct mbuf *, int);
+struct mbuf	*m_split(struct mbuf *, int, int);
+struct mbuf	*m_unshare(struct mbuf *, int how);
+#else
+void		 m_freem(PNATState pData, struct mbuf *);
+struct mbuf	*m_getm2(PNATState pData, struct mbuf *, int, int, short, int);
+struct mbuf	*m_prepend(PNATState, struct mbuf *, int, int);
+struct mbuf	*m_pulldown(PNATState, struct mbuf *, int, int, int *);
+struct mbuf	*m_pullup(PNATState, struct mbuf *, int);
+int		m_sanity(PNATState, struct mbuf *, int);
+struct mbuf	*m_split(PNATState, struct mbuf *, int, int);
+struct mbuf	*m_unshare(PNATState, struct mbuf *, int how);
+#endif
+struct mbuf	*m_getptr(struct mbuf *, int, int *);
+u_int		 m_length(struct mbuf *, struct mbuf **);
+void		 m_move_pkthdr(struct mbuf *, struct mbuf *);
+void		 m_print(const struct mbuf *, int);
+struct mbuf	*m_uiotombuf(struct uio *, int, int, int, int);
+
+/*-
+ * Network packets may have annotations attached by affixing a list of
+ * "packet tags" to the pkthdr structure.  Packet tags are dynamically
+ * allocated semi-opaque data structures that have a fixed header
+ * (struct m_tag) that specifies the size of the memory block and a
+ * <cookie,type> pair that identifies it.  The cookie is a 32-bit unique
+ * unsigned value used to identify a module or ABI.  By convention this value
+ * is chosen as the date+time that the module is created, expressed as the
+ * number of seconds since the epoch (e.g., using date -u +'%s').  The type
+ * value is an ABI/module-specific value that identifies a particular
+ * annotation and is private to the module.  For compatibility with systems
+ * like OpenBSD that define packet tags w/o an ABI/module cookie, the value
+ * PACKET_ABI_COMPAT is used to implement m_tag_get and m_tag_find
+ * compatibility shim functions and several tag types are defined below.
+ * Users that do not require compatibility should use a private cookie value
+ * so that packet tag-related definitions can be maintained privately.
+ *
+ * Note that the packet tag returned by m_tag_alloc has the default memory
+ * alignment implemented by malloc.  To reference private data one can use a
+ * construct like:
+ *
+ *	struct m_tag *mtag = m_tag_alloc(...);
+ *	struct foo *p = (struct foo *)(mtag+1);
+ *
+ * if the alignment of struct m_tag is sufficient for referencing members of
+ * struct foo.  Otherwise it is necessary to embed struct m_tag within the
+ * private data structure to insure proper alignment; e.g.,
+ *
+ *	struct foo {
+ *		struct m_tag	tag;
+ *		...
+ *	};
+ *	struct foo *p = (struct foo *) m_tag_alloc(...);
+ *	struct m_tag *mtag = &p->tag;
+ */
+
+/*
+ * Persistent tags stay with an mbuf until the mbuf is reclaimed.  Otherwise
+ * tags are expected to ``vanish'' when they pass through a network
+ * interface.  For most interfaces this happens normally as the tags are
+ * reclaimed when the mbuf is free'd.  However in some special cases
+ * reclaiming must be done manually.  An example is packets that pass through
+ * the loopback interface.  Also, one must be careful to do this when
+ * ``turning around'' packets (e.g., icmp_reflect).
+ *
+ * To mark a tag persistent bit-or this flag in when defining the tag id.
+ * The tag will then be treated as described above.
+ */
+#define	MTAG_PERSISTENT				0x800
+
+#define	PACKET_TAG_NONE				0  /* Nadda */
+
+/* Packet tags for use with PACKET_ABI_COMPAT. */
+#define	PACKET_TAG_IPSEC_IN_DONE		1  /* IPsec applied, in */
+#define	PACKET_TAG_IPSEC_OUT_DONE		2  /* IPsec applied, out */
+#define	PACKET_TAG_IPSEC_IN_CRYPTO_DONE		3  /* NIC IPsec crypto done */
+#define	PACKET_TAG_IPSEC_OUT_CRYPTO_NEEDED	4  /* NIC IPsec crypto req'ed */
+#define	PACKET_TAG_IPSEC_IN_COULD_DO_CRYPTO	5  /* NIC notifies IPsec */
+#define	PACKET_TAG_IPSEC_PENDING_TDB		6  /* Reminder to do IPsec */
+#define	PACKET_TAG_BRIDGE			7  /* Bridge processing done */
+#define	PACKET_TAG_GIF				8  /* GIF processing done */
+#define	PACKET_TAG_GRE				9  /* GRE processing done */
+#define	PACKET_TAG_IN_PACKET_CHECKSUM		10 /* NIC checksumming done */
+#define	PACKET_TAG_ENCAP			11 /* Encap.  processing */
+#define	PACKET_TAG_IPSEC_SOCKET			12 /* IPSEC socket ref */
+#define	PACKET_TAG_IPSEC_HISTORY		13 /* IPSEC history */
+#define	PACKET_TAG_IPV6_INPUT			14 /* IPV6 input processing */
+#define	PACKET_TAG_DUMMYNET			15 /* dummynet info */
+#define	PACKET_TAG_DIVERT			17 /* divert info */
+#define	PACKET_TAG_IPFORWARD			18 /* ipforward info */
+#define	PACKET_TAG_MACLABEL	(19 | MTAG_PERSISTENT) /* MAC label */
+#define	PACKET_TAG_PF				21 /* PF + ALTQ information */
+#define	PACKET_TAG_RTSOCKFAM			25 /* rtsock sa family */
+#define	PACKET_TAG_IPOPTIONS			27 /* Saved IP options */
+#define	PACKET_TAG_CARP                         28 /* CARP info */
+#ifdef VBOX
+#define	PACKET_TAG_ALIAS                        0xab01
+#define	PACKET_TAG_ETHER                        0xab02
+#endif
+
+/* Specific cookies and tags. */
+
+/* Packet tag routines. */
+struct m_tag	*m_tag_alloc(u_int32_t, int, int, int);
+void		 m_tag_delete(struct mbuf *, struct m_tag *);
+void		 m_tag_delete_chain(struct mbuf *, struct m_tag *);
+void		 m_tag_free_default(struct m_tag *);
+struct m_tag	*m_tag_locate(struct mbuf *, u_int32_t, int, struct m_tag *);
+struct m_tag	*m_tag_copy(struct m_tag *, int);
+int		 m_tag_copy_chain(struct mbuf *, struct mbuf *, int);
+void		 m_tag_delete_nonpersistent(struct mbuf *);
+
+/*
+ * Initialize the list of tags associated with an mbuf.
+ */
+static __inline void
+m_tag_init(struct mbuf *m)
+{
+
+	SLIST_INIT(&m->m_pkthdr.tags);
+}
+
+/*
+ * Set up the contents of a tag.  Note that this does not fill in the free
+ * method; the caller is expected to do that.
+ *
+ * XXX probably should be called m_tag_init, but that was already taken.
+ */
+static __inline void
+m_tag_setup(struct m_tag *t, u_int32_t cookie, int type, int len)
+{
+
+	t->m_tag_id = type;
+	t->m_tag_len = len;
+	t->m_tag_cookie = cookie;
+}
+
+/*
+ * Reclaim resources associated with a tag.
+ */
+static __inline void
+m_tag_free(struct m_tag *t)
+{
+
+	(*t->m_tag_free)(t);
+}
+
+/*
+ * Return the first tag associated with an mbuf.
+ */
+static __inline struct m_tag *
+m_tag_first(struct mbuf *m)
+{
+
+	return (SLIST_FIRST(&m->m_pkthdr.tags));
+}
+
+/*
+ * Return the next tag in the list of tags associated with an mbuf.
+ */
+static __inline struct m_tag *
+m_tag_next(struct mbuf *m, struct m_tag *t)
+{
+
+	return (SLIST_NEXT(t, m_tag_link));
+}
+
+/*
+ * Prepend a tag to the list of tags associated with an mbuf.
+ */
+static __inline void
+m_tag_prepend(struct mbuf *m, struct m_tag *t)
+{
+
+	SLIST_INSERT_HEAD(&m->m_pkthdr.tags, t, m_tag_link);
+}
+
+/*
+ * Unlink a tag from the list of tags associated with an mbuf.
+ */
+static __inline void
+m_tag_unlink(struct mbuf *m, struct m_tag *t)
+{
+
+	SLIST_REMOVE(&m->m_pkthdr.tags, t, m_tag, m_tag_link);
+}
+
+/* These are for OpenBSD compatibility. */
+#define	MTAG_ABI_COMPAT		0		/* compatibility ABI */
+
+static __inline struct m_tag *
+m_tag_get(int type, int length, int wait)
+{
+	return (m_tag_alloc(MTAG_ABI_COMPAT, type, length, wait));
+}
+
+static __inline struct m_tag *
+m_tag_find(struct mbuf *m, int type, struct m_tag *start)
+{
+	return (SLIST_EMPTY(&m->m_pkthdr.tags) ? (struct m_tag *)NULL :
+	    m_tag_locate(m, MTAG_ABI_COMPAT, type, start));
+}
+
+/* XXX temporary FIB methods probably eventually use tags.*/
+#define M_FIBSHIFT    28
+#define M_FIBMASK	0x0F
+
+/* get the fib from an mbuf and if it is not set, return the default */
+#define M_GETFIB(_m) \
+    ((((_m)->m_flags & M_FIB) >> M_FIBSHIFT) & M_FIBMASK)
+
+#define M_SETFIB(_m, _fib) do {						\
+	_m->m_flags &= ~M_FIB;					   	\
+	_m->m_flags |= (((_fib) << M_FIBSHIFT) & M_FIB);  \
+} while (0)
+
+#endif /* _KERNEL */
+
+#endif /* !_SYS_MBUF_H_ */
Index: trunk/src/VBox/Devices/Network/slirp/libalias/HISTORY
===================================================================
--- trunk/src/VBox/Devices/Network/slirp/libalias/HISTORY	(revision 27869)
+++ trunk/src/VBox/Devices/Network/slirp/libalias/HISTORY	(revision 27869)
@@ -0,0 +1,145 @@
+$FreeBSD: src/sys/netinet/libalias/HISTORY,v 1.9.32.1 2009/04/15 03:14:26 kensmith Exp $
+
+Version 1.0: August 11, 1996 (cjm)
+
+Version 1.1:  August 20, 1996  (cjm)
+    - Host accepts incoming connections for ports 0 to 1023.
+
+Version 1.2:  September 7, 1996 (cjm)
+    - Fragment handling error in alias_db.c corrected.
+
+Version 1.3:  September 15, 1996 (cjm)
+    - Generalized mechanism for handling incoming
+      connections (no more 0 to 1023 restriction).
+
+    - Increased ICMP support (will handle traceroute now).
+
+    - Improved TCP close connection logic.
+
+Version 1.4: September 16, 1996 (cjm)
+
+Version 1.5: September 17, 1996 (cjm)
+    - Corrected error in handling incoming UDP packets
+      with zero checksum.
+
+Version 1.6: September 18, 1996
+    - Simplified ICMP data storage.  Will now handle
+      tracert from Win95 and NT as well as FreeBSD
+      traceroute, which uses UDP packets to non-existent
+      ports.
+
+Version 1.7: January 9, 1997 (cjm)
+    - Reduced malloc() activity for ICMP echo and
+      timestamp requests.
+
+    - Added handling for out-of-order IP fragments.
+
+    - Switched to differential checksum computation
+      for IP headers (TCP, UDP and ICMP checksums
+      were already differential).
+
+    - Accepts FTP data connections from other than
+      port 20.  This allows one ftp connections
+      from two hosts which are both running packet
+      aliasing.
+
+    - Checksum error on FTP transfers.  Problem
+      in code located by Martin Renters and
+      Brian Somers.
+
+Version 1.8: January 14, 1997 (cjm)
+    - Fixed data type error in function StartPoint()
+      in alias_db.c (this bug did not exist before v1.7)
+      Problem in code located by Ari Suutari.
+
+Version 1.9: February 1, 1997 (Eivind Eklund <perhaps@yes.no>)
+    - Added support for IRC DCC (ee)
+
+    - Changed the aliasing routines to use ANSI style
+      throughout (ee)
+
+    - Minor API changes for integration with other
+      programs than PPP (ee)
+
+    - Fixed minor security hole in alias_ftp.c for
+      other applications of the aliasing software.
+      Hole could _not_ manifest in ppp+pktAlias, but
+      could potentially manifest in other applications
+      of the aliasing. (ee)
+
+    - Connections initiated from packet aliasing
+      host machine will not have their port number
+      aliased unless it conflicts with an aliasing
+      port already being used. (There is an option
+      to disable this for debugging) (cjm)
+
+    - Sockets will be allocated in cases where
+      there might be port interference with the
+      host machine.  This can be disabled in cases
+      where the ppp host will be acting purely as a
+      masquerading router and not generate any
+      traffic of its own.
+      (cjm)
+
+Version 2.0: March, 1997 (cjm)
+    - Aliasing links are cleared only when a host interface address
+      changes.
+
+    - PacketAliasPermanentLink() API added.
+
+    - Option for only aliasing private, unregistered
+      IP addresses added.
+
+    - Substantial rework to the aliasing lookup engine.
+
+Version 2.1: May, 1997 (cjm)
+    - Continuing rework to the aliasing lookup engine
+      to support multiple incoming addresses and static
+      NAT.  PacketAliasRedirectPort() and
+      PacketAliasRedirectAddr() added to API.
+
+    - Now supports outgoing as well as incoming ICMP
+      error messages.
+
+Version 2.2: July, 1997 (cjm)
+    - Rationalized API function names to all begin with
+      "PacketAlias..."  Old function names are retained
+      for backwards compatibility.
+
+    - Packet aliasing engine will now free memory of
+      fragments which are never resolved after a timeout
+      period.  Once a fragment is resolved, it becomes
+      the users responsibility to free the memory.
+
+Version 2.3: August 11, 1997 (cjm)
+    - Problem associated with socket file descriptor
+      accumulation in alias_db.c corrected.  The sockets
+      had to be closed when a binding failed.  Problem 
+      in code located by Gordon Burditt.
+
+Version 2.4: September 1, 1997 (cjm)
+    - PKT_ALIAS_UNREGISTERED_ONLY option repaired.
+      This part of the code was incorrectly re-implemented
+      in version 2.1.
+
+Version 2.5: December, 1997 (ee)
+    - Added PKT_ALIAS_PUNCH_FW mode for firewall
+      bypass of FTP/IRC DCC data connections.  Also added
+      improved TCP connection monitoring.
+
+Version 2.6: May, 1998 (amurai)
+    - Added supporting routine for NetBios over TCP/IP.
+
+Version 3.0: January 1, 1999
+    - Transparent proxying support added.
+    - PPTP redirecting support added based on patches
+      contributed by Dru Nelson <dnelson@redwoodsoft.com>.
+
+Version 3.1: May, 2000 (Erik Salander, erik@whistle.com)
+    - Added support to alias 227 replies, allows aliasing for
+      FTP servers in passive mode.
+    - Added support for PPTP aliasing.
+
+Version 3.2: July, 2000 (Erik Salander, erik@whistle.com and 
+      Junichi Satoh, junichi@junichi.org)
+    - Added support for streaming media (RTSP and PNA) aliasing.
Index: trunk/src/VBox/Devices/Network/slirp/libalias/libalias.3
===================================================================
--- trunk/src/VBox/Devices/Network/slirp/libalias/libalias.3	(revision 27869)
+++ trunk/src/VBox/Devices/Network/slirp/libalias/libalias.3	(revision 27869)
@@ -0,0 +1,1458 @@
+.\"-
+.\" Copyright (c) 2001 Charles Mott <cm@linktel.net>
+.\" 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
+.\"    documentation and/or other materials provided with the distribution.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE AUTHOR 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 AUTHOR 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.
+.\"
+.\" $FreeBSD: src/sys/netinet/libalias/libalias.3,v 1.58.8.1 2009/04/15 03:14:26 kensmith Exp $
+.\"
+.Dd October 1, 2006
+.Dt LIBALIAS 3
+.Os
+.Sh NAME
+.Nm libalias
+.Nd packet aliasing library for masquerading and network address translation
+.Sh SYNOPSIS
+.In sys/types.h
+.In netinet/in.h
+.In alias.h
+.Pp
+Function prototypes are given in the main body of the text.
+.Sh DESCRIPTION
+The
+.Nm
+library is a collection of functions for aliasing and de-aliasing of IP
+packets, intended for masquerading and network address translation (NAT).
+.Sh INTRODUCTION
+This library is a moderately portable set of functions designed to assist
+in the process of IP masquerading and network address translation.
+Outgoing packets from a local network with unregistered IP addresses can
+be aliased to appear as if they came from an accessible IP address.
+Incoming packets are then de-aliased so that they are sent to the correct
+machine on the local network.
+.Pp
+A certain amount of flexibility is built into the packet aliasing engine.
+In the simplest mode of operation, a many-to-one address mapping takes
+place between local network and the packet aliasing host.
+This is known as IP masquerading.
+In addition, one-to-one mappings between local and public addresses can
+also be implemented, which is known as static NAT.
+In between these extremes, different groups of private addresses can be
+linked to different public addresses, comprising several distinct
+many-to-one mappings.
+Also, a given public address and port can be statically redirected to a
+private address/port.
+.Pp
+The packet aliasing engine was designed to operate in user space outside
+of the kernel, without any access to private kernel data structure, but
+the source code can also be ported to a kernel environment.
+.Sh INITIALIZATION AND CONTROL
+One special function,
+.Fn LibAliasInit ,
+must always be called before any packet handling may be performed and
+the returned instance pointer passed to all the other functions.
+Normally, the
+.Fn LibAliasSetAddress
+function is called afterwards, to set the default aliasing address.
+In addition, the operating mode of the packet aliasing engine can be
+customized by calling
+.Fn LibAliasSetMode .
+.Pp
+.Ft "struct libalias *"
+.Fn LibAliasInit "struct libalias *"
+.Bd -ragged -offset indent
+This function is used to initialize
+internal data structures.
+When called the first time, a
+.Dv NULL
+pointer should be passed as an argument.
+The following mode bits are always set after calling
+.Fn LibAliasInit .
+See the description of
+.Fn LibAliasSetMode
+below for the meaning of these mode bits.
+.Pp
+.Bl -item -offset indent -compact
+.It
+.Dv PKT_ALIAS_SAME_PORTS
+.It
+.Dv PKT_ALIAS_USE_SOCKETS
+.It
+.Dv PKT_ALIAS_RESET_ON_ADDR_CHANGE
+.El
+.Pp
+This function will always return the packet aliasing engine to the same
+initial state.
+The
+.Fn LibAliasSetAddress
+function is normally called afterwards, and any desired changes from the
+default mode bits listed above require a call to
+.Fn LibAliasSetMode .
+.Pp
+It is mandatory that this function be called at the beginning of a program
+prior to any packet handling.
+.Ed
+.Pp
+.Ft void
+.Fn LibAliasUninit "struct libalias *"
+.Bd -ragged -offset indent
+This function has no return value and is used to clear any
+resources attached to internal data structures.
+.Pp
+This functions should be called when a program stops using the aliasing
+engine; it does, amongst other things, clear out any firewall holes.
+To provide backwards compatibility and extra security, it is added to
+the
+.Xr atexit 3
+chain by
+.Fn LibAliasInit .
+.Ed
+.Pp
+.Ft void
+.Fn LibAliasSetAddress "struct libalias *" "struct in_addr addr"
+.Bd -ragged -offset indent
+This function sets the source address to which outgoing packets from the
+local area network are aliased.
+All outgoing packets are re-mapped to this address unless overridden by a
+static address mapping established by
+.Fn LibAliasRedirectAddr .
+If this function is not called, and no static rules match, an outgoing
+packet retains its source address.
+.Pp
+If the
+.Dv PKT_ALIAS_RESET_ON_ADDR_CHANGE
+mode bit is set (the default mode of operation), then the internal aliasing
+link tables will be reset any time the aliasing address changes.
+This is useful for interfaces such as
+.Xr ppp 8 ,
+where the IP
+address may or may not change on successive dial-up attempts.
+.Pp
+If the
+.Dv PKT_ALIAS_RESET_ON_ADDR_CHANGE
+mode bit is set to zero, this function can also be used to dynamically change
+the aliasing address on a packet to packet basis (it is a low overhead call).
+.Pp
+It is mandatory that this function be called prior to any packet handling.
+.Ed
+.Pp
+.Ft unsigned int
+.Fn LibAliasSetMode "struct libalias *" "unsigned int flags" "unsigned int mask"
+.Bd -ragged -offset indent
+This function sets or clears mode bits
+according to the value of
+.Fa flags .
+Only bits marked in
+.Fa mask
+are affected.
+The following mode bits are defined in
+.In alias.h :
+.Bl -tag -width indent
+.It Dv PKT_ALIAS_LOG
+Enables logging into
+.Pa /var/log/alias.log .
+Each time an aliasing link is created or deleted, the log file is appended
+with the current number of ICMP, TCP and UDP links.
+Mainly useful for debugging when the log file is viewed continuously with
+.Xr tail 1 .
+.It Dv PKT_ALIAS_DENY_INCOMING
+If this mode bit is set, all incoming packets associated with new TCP
+connections or new UDP transactions will be marked for being ignored
+.Fn ( LibAliasIn
+returns
+.Dv PKT_ALIAS_IGNORED
+code)
+by the calling program.
+Response packets to connections or transactions initiated from the packet
+aliasing host or local network will be unaffected.
+This mode bit is useful for implementing a one-way firewall.
+.It Dv PKT_ALIAS_SAME_PORTS
+If this mode bit is set, the packet aliasing engine will attempt to leave
+the alias port numbers unchanged from the actual local port numbers.
+This can be done as long as the quintuple (proto, alias addr, alias port,
+remote addr, remote port) is unique.
+If a conflict exists, a new aliasing port number is chosen even if this
+mode bit is set.
+.It Dv PKT_ALIAS_USE_SOCKETS
+This bit should be set when the packet aliasing host originates network
+traffic as well as forwards it.
+When the packet aliasing host is waiting for a connection from an unknown
+host address or unknown port number (e.g.\& an FTP data connection), this
+mode bit specifies that a socket be allocated as a place holder to prevent
+port conflicts.
+Once a connection is established, usually within a minute or so, the socket
+is closed.
+.It Dv PKT_ALIAS_UNREGISTERED_ONLY
+If this mode bit is set, traffic on the local network which does not
+originate from unregistered address spaces will be ignored.
+Standard Class A, B and C unregistered addresses are:
+.Bd -literal -offset indent
+10.0.0.0     ->  10.255.255.255   (Class A subnet)
+172.16.0.0   ->  172.31.255.255   (Class B subnets)
+192.168.0.0  ->  192.168.255.255  (Class C subnets)
+.Ed
+.Pp
+This option is useful in the case that packet aliasing host has both
+registered and unregistered subnets on different interfaces.
+The registered subnet is fully accessible to the outside world, so traffic
+from it does not need to be passed through the packet aliasing engine.
+.It Dv PKT_ALIAS_RESET_ON_ADDR_CHANGE
+When this mode bit is set and
+.Fn LibAliasSetAddress
+is called to change the aliasing address, the internal link table of the
+packet aliasing engine will be cleared.
+This operating mode is useful for
+.Xr ppp 8
+links where the interface address can sometimes change or remain the same
+between dial-up attempts.
+If this mode bit is not set, the link table will never be reset in the event
+of an address change.
+.It Dv PKT_ALIAS_PUNCH_FW
+This option makes
+.Nm
+`punch holes' in an
+.Xr ipfirewall 4
+based firewall for FTP/IRC DCC connections.
+The holes punched are bound by from/to IP address and port; it will not be
+possible to use a hole for another connection.
+A hole is removed when the connection that uses it dies.
+To cater to unexpected death of a program using
+.Nm
+(e.g.\& kill -9),
+changing the state of the flag will clear the entire firewall range
+allocated for holes.
+This will also happen on the initial call to
+.Fn LibAliasSetFWBase .
+This call must happen prior to setting this flag.
+.It Dv PKT_ALIAS_REVERSE
+This option makes
+.Nm
+reverse the way it handles incoming and outgoing packets, allowing it
+to be fed with data that passes through the internal interface rather
+than the external one.
+.It Dv PKT_ALIAS_PROXY_ONLY
+This option tells
+.Nm
+to obey transparent proxy rules only.
+Normal packet aliasing is not performed.
+See
+.Fn LibAliasProxyRule
+below for details.
+.El
+.Ed
+.Pp
+.Ft void
+.Fn LibAliasSetFWBase "struct libalias *" "unsigned int base" "unsigned int num"
+.Bd -ragged -offset indent
+Set firewall range allocated for punching firewall holes (with the
+.Dv PKT_ALIAS_PUNCH_FW
+flag).
+The range will be cleared for all rules on initialization.
+.Ed
+.Pp
+.Ft void
+.Fn LibAliasSkinnyPort "struct libalias *" "unsigned int port"
+.Bd -ragged -offset indent
+Set the TCP port used by the Skinny Station protocol.
+Skinny is used by Cisco IP phones to communicate with
+Cisco Call Managers to set up voice over IP calls.
+If this is not set, Skinny aliasing will not be done.
+The typical port used by Skinny is 2000.
+.Ed
+.Sh PACKET HANDLING
+The packet handling functions are used to modify incoming (remote to local)
+and outgoing (local to remote) packets.
+The calling program is responsible for receiving and sending packets via
+network interfaces.
+.Pp
+Along with
+.Fn LibAliasInit
+and
+.Fn LibAliasSetAddress ,
+the two packet handling functions,
+.Fn LibAliasIn
+and
+.Fn LibAliasOut ,
+comprise minimal set of functions needed for a basic IP masquerading
+implementation.
+.Pp
+.Ft int
+.Fn LibAliasIn "struct libalias *" "char *buffer" "int maxpacketsize"
+.Bd -ragged -offset indent
+An incoming packet coming from a remote machine to the local network is
+de-aliased by this function.
+The IP packet is pointed to by
+.Fa buffer ,
+and
+.Fa maxpacketsize
+indicates the size of the data structure containing the packet and should
+be at least as large as the actual packet size.
+.Pp
+Return codes:
+.Bl -tag -width indent
+.It Dv PKT_ALIAS_OK
+The packet aliasing process was successful.
+.It Dv PKT_ALIAS_IGNORED
+The packet was ignored and not de-aliased.
+This can happen if the protocol is unrecognized, possibly an ICMP message
+type is not handled or if incoming packets for new connections are being
+ignored (if
+.Dv PKT_ALIAS_DENY_INCOMING
+mode bit was set by
+.Fn LibAliasSetMode ) .
+.It Dv PKT_ALIAS_UNRESOLVED_FRAGMENT
+This is returned when a fragment cannot be resolved because the header
+fragment has not been sent yet.
+In this situation, fragments must be saved with
+.Fn LibAliasSaveFragment
+until a header fragment is found.
+.It Dv PKT_ALIAS_FOUND_HEADER_FRAGMENT
+The packet aliasing process was successful, and a header fragment was found.
+This is a signal to retrieve any unresolved fragments with
+.Fn LibAliasGetFragment
+and de-alias them with
+.Fn LibAliasFragmentIn .
+.It Dv PKT_ALIAS_ERROR
+An internal error within the packet aliasing engine occurred.
+.El
+.Ed
+.Pp
+.Ft int
+.Fn LibAliasOut "struct libalias *" "char *buffer" "int maxpacketsize"
+.Bd -ragged -offset indent
+An outgoing packet coming from the local network to a remote machine is
+aliased by this function.
+The IP packet is pointed to by
+.Fa buffer ,
+and
+.Fa maxpacketsize
+indicates the maximum packet size permissible should the packet length be
+changed.
+IP encoding protocols place address and port information in the encapsulated
+data stream which has to be modified and can account for changes in packet
+length.
+Well known examples of such protocols are FTP and IRC DCC.
+.Pp
+Return codes:
+.Bl -tag -width indent
+.It Dv PKT_ALIAS_OK
+The packet aliasing process was successful.
+.It Dv PKT_ALIAS_IGNORED
+The packet was ignored and not aliased.
+This can happen if the protocol is unrecognized, or possibly an ICMP message
+type is not handled.
+.It Dv PKT_ALIAS_ERROR
+An internal error within the packet aliasing engine occurred.
+.El
+.Ed
+.Sh PORT AND ADDRESS REDIRECTION
+The functions described in this section allow machines on the local network
+to be accessible in some degree to new incoming connections from the external
+network.
+Individual ports can be re-mapped or static network address translations can
+be designated.
+.Pp
+.Ft struct alias_link *
+.Fo LibAliasRedirectPort
+.Fa "struct libalias *"
+.Fa "struct in_addr local_addr"
+.Fa "u_short local_port"
+.Fa "struct in_addr remote_addr"
+.Fa "u_short remote_port"
+.Fa "struct in_addr alias_addr"
+.Fa "u_short alias_port"
+.Fa "u_char proto"
+.Fc
+.Bd -ragged -offset indent
+This function specifies that traffic from a given remote address/port to
+an alias address/port be redirected to a specified local address/port.
+The parameter
+.Fa proto
+can be either
+.Dv IPPROTO_TCP
+or
+.Dv IPPROTO_UDP ,
+as defined in
+.In netinet/in.h .
+.Pp
+If
+.Fa local_addr
+or
+.Fa alias_addr
+is zero, this indicates that the packet aliasing address as established
+by
+.Fn LibAliasSetAddress
+is to be used.
+Even if
+.Fn LibAliasSetAddress
+is called to change the address after
+.Fn LibAliasRedirectPort
+is called, a zero reference will track this change.
+.Pp
+If the link is further set up to operate for a load sharing, then
+.Fa local_addr
+and
+.Fa local_port
+are ignored, and are selected dynamically from the server pool, as described in
+.Fn LibAliasAddServer
+below.
+.Pp
+If
+.Fa remote_addr
+is zero, this indicates to redirect packets from any remote address.
+Likewise, if
+.Fa remote_port
+is zero, this indicates to redirect packets originating from any remote
+port number.
+Almost always, the remote port specification will be zero, but non-zero
+remote addresses can sometimes be useful for firewalling.
+If two calls to
+.Fn LibAliasRedirectPort
+overlap in their address/port specifications, then the most recent call
+will have precedence.
+.Pp
+This function returns a pointer which can subsequently be used by
+.Fn LibAliasRedirectDelete .
+If
+.Dv NULL
+is returned, then the function call did not complete successfully.
+.Pp
+All port numbers should be in network address byte order, so it is necessary
+to use
+.Xr htons 3
+to convert these parameters from internally readable numbers to network byte
+order.
+Addresses are also in network byte order, which is implicit in the use of the
+.Fa struct in_addr
+data type.
+.Ed
+.Pp
+.Ft struct alias_link *
+.Fo LibAliasRedirectAddr
+.Fa "struct libalias *"
+.Fa "struct in_addr local_addr"
+.Fa "struct in_addr alias_addr"
+.Fc
+.Bd -ragged -offset indent
+This function designates that all incoming traffic to
+.Fa alias_addr
+be redirected to
+.Fa local_addr .
+Similarly, all outgoing traffic from
+.Fa local_addr
+is aliased to
+.Fa alias_addr .
+.Pp
+If
+.Fa local_addr
+or
+.Fa alias_addr
+is zero, this indicates that the packet aliasing address as established by
+.Fn LibAliasSetAddress
+is to be used.
+Even if
+.Fn LibAliasSetAddress
+is called to change the address after
+.Fn LibAliasRedirectAddr
+is called, a zero reference will track this change.
+.Pp
+If the link is further set up to operate for a load sharing, then
+.Fa local_addr
+is ignored, and is selected dynamically from the server pool, as described in
+.Fn LibAliasAddServer
+below.
+.Pp
+If subsequent calls to
+.Fn LibAliasRedirectAddr
+use the same aliasing address, all new incoming traffic to this aliasing
+address will be redirected to the local address made in the last function
+call.
+New traffic generated by any of the local machines, designated in the
+several function calls, will be aliased to the same address.
+Consider the following example:
+.Bd -literal -offset indent
+LibAliasRedirectAddr(la, inet_aton("192.168.0.2"),
+                        inet_aton("141.221.254.101"));
+LibAliasRedirectAddr(la, inet_aton("192.168.0.3"),
+                        inet_aton("141.221.254.101"));
+LibAliasRedirectAddr(la, inet_aton("192.168.0.4"),
+                        inet_aton("141.221.254.101"));
+.Ed
+.Pp
+Any outgoing connections such as
+.Xr telnet 1
+or
+.Xr ftp 1
+from 192.168.0.2, 192.168.0.3 and 192.168.0.4 will appear to come from
+141.221.254.101.
+Any incoming connections to 141.221.254.101 will be directed to 192.168.0.4.
+.Pp
+Any calls to
+.Fn LibAliasRedirectPort
+will have precedence over address mappings designated by
+.Fn LibAliasRedirectAddr .
+.Pp
+This function returns a pointer which can subsequently be used by
+.Fn LibAliasRedirectDelete .
+If
+.Dv NULL
+is returned, then the function call did not complete successfully.
+.Ed
+.Pp
+.Ft int
+.Fo LibAliasAddServer
+.Fa "struct libalias *"
+.Fa "struct alias_link *link"
+.Fa "struct in_addr addr"
+.Fa "u_short port"
+.Fc
+.Bd -ragged -offset indent
+This function sets the
+.Fa link
+up for Load Sharing using IP Network Address Translation (RFC 2391, LSNAT).
+LSNAT operates as follows.
+A client attempts to access a server by using the server virtual address.
+The LSNAT router transparently redirects the request to one of the hosts
+in server pool, selected using a real-time load sharing algorithm.
+Multiple sessions may be initiated from the same client, and each session
+could be directed to a different host based on load balance across server
+pool hosts at the time.
+If load share is desired for just a few specific services, the configuration
+on LSNAT could be defined to restrict load share for just the services
+desired.
+.Pp
+Currently, only the simplest selection algorithm is implemented, where a
+host is selected on a round-robin basis only, without regard to load on
+the host.
+.Pp
+First, the
+.Fa link
+is created by either
+.Fn LibAliasRedirectPort
+or
+.Fn LibAliasRedirectAddr .
+Then,
+.Fn LibAliasAddServer
+is called multiple times to add entries to the
+.Fa link Ns 's
+server pool.
+.Pp
+For links created with
+.Fn LibAliasRedirectAddr ,
+the
+.Fa port
+argument is ignored and could have any value, e.g.\& htons(~0).
+.Pp
+This function returns 0 on success, \-1 otherwise.
+.Ed
+.Pp
+.Ft int
+.Fn LibAliasRedirectDynamic "struct libalias *" "struct alias_link *link"
+.Bd -ragged -offset indent
+This function marks the specified static redirect rule entered by
+.Fn LibAliasRedirectPort
+as dynamic.
+This can be used to e.g.\& dynamically redirect a single TCP connection,
+after which the rule is removed.
+Only fully specified links can be made dynamic.
+(See the
+.Sx STATIC AND DYNAMIC LINKS
+and
+.Sx PARTIALLY SPECIFIED ALIASING LINKS
+sections below for a definition of static vs.\& dynamic,
+and partially vs.\& fully specified links.)
+.Pp
+This function returns 0 on success, \-1 otherwise.
+.Ed
+.Pp
+.Ft void
+.Fn LibAliasRedirectDelete "struct libalias *" "struct alias_link *link"
+.Bd -ragged -offset indent
+This function will delete a specific static redirect rule entered by
+.Fn LibAliasRedirectPort
+or
+.Fn LibAliasRedirectAddr .
+The parameter
+.Fa link
+is the pointer returned by either of the redirection functions.
+If an invalid pointer is passed to
+.Fn LibAliasRedirectDelete ,
+then a program crash or unpredictable operation could result, so it is
+necessary to be careful using this function.
+.Ed
+.Pp
+.Ft int
+.Fn LibAliasProxyRule "struct libalias *" "const char *cmd"
+.Bd -ragged -offset indent
+The passed
+.Fa cmd
+string consists of one or more pairs of words.
+The first word in each pair is a token and the second is the value that
+should be applied for that token.
+Tokens and their argument types are as follows:
+.Bl -tag -width indent
+.It Cm type encode_ip_hdr | encode_tcp_stream | no_encode
+In order to support transparent proxying, it is necessary to somehow
+pass the original address and port information into the new destination
+server.
+If
+.Cm encode_ip_hdr
+is specified, the original destination address and port are passed
+as an extra IP option.
+If
+.Cm encode_tcp_stream
+is specified, the original destination address and port are passed
+as the first piece of data in the TCP stream in the format
+.Dq Li DEST Ar IP port .
+.It Cm port Ar portnum
+Only packets with the destination port
+.Ar portnum
+are proxied.
+.It Cm server Ar host Ns Op : Ns Ar portnum
+This specifies the
+.Ar host
+and
+.Ar portnum
+that the data is to be redirected to.
+.Ar host
+must be an IP address rather than a DNS host name.
+If
+.Ar portnum
+is not specified, the destination port number is not changed.
+.Pp
+The
+.Ar server
+specification is mandatory unless the
+.Cm delete
+command is being used.
+.It Cm rule Ar index
+Normally, each call to
+.Fn LibAliasProxyRule
+inserts the next rule at the start of a linear list of rules.
+If an
+.Ar index
+is specified, the new rule will be checked after all rules with lower
+indices.
+Calls to
+.Fn LibAliasProxyRule
+that do not specify a rule are assigned rule 0.
+.It Cm delete Ar index
+This token and its argument MUST NOT be used with any other tokens.
+When used, all existing rules with the given
+.Ar index
+are deleted.
+.It Cm proto tcp | udp
+If specified, only packets of the given protocol type are matched.
+.It Cm src Ar IP Ns Op / Ns Ar bits
+If specified, only packets with a source address matching the given
+.Ar IP
+are matched.
+If
+.Ar bits
+is also specified, then the first
+.Ar bits
+bits of
+.Ar IP
+are taken as a network specification, and all IP addresses from that
+network will be matched.
+.It Cm dst Ar IP Ns Op / Ns Ar bits
+If specified, only packets with a destination address matching the given
+.Ar IP
+are matched.
+If
+.Ar bits
+is also specified, then the first
+.Ar bits
+bits of
+.Ar IP
+are taken as a network specification, and all IP addresses from that
+network will be matched.
+.El
+.Pp
+This function is usually used to redirect outgoing connections for
+internal machines that are not permitted certain types of internet
+access, or to restrict access to certain external machines.
+.Ed
+.Pp
+.Ft struct alias_link *
+.Fo LibAliasRedirectProto
+.Fa "struct libalias *"
+.Fa "struct in_addr local_addr"
+.Fa "struct in_addr remote_addr"
+.Fa "struct in_addr alias_addr"
+.Fa "u_char proto"
+.Fc
+.Bd -ragged -offset indent
+This function specifies that any IP packet with protocol number of
+.Fa proto
+from a given remote address to an alias address be
+redirected to a specified local address.
+.Pp
+If
+.Fa local_addr
+or
+.Fa alias_addr
+is zero, this indicates that the packet aliasing address as established
+by
+.Fn LibAliasSetAddress
+is to be used.
+Even if
+.Fn LibAliasSetAddress
+is called to change the address after
+.Fn LibAliasRedirectProto
+is called, a zero reference will track this change.
+.Pp
+If
+.Fa remote_addr
+is zero, this indicates to redirect packets from any remote address.
+Non-zero remote addresses can sometimes be useful for firewalling.
+.Pp
+If two calls to
+.Fn LibAliasRedirectProto
+overlap in their address specifications, then the most recent call
+will have precedence.
+.Pp
+This function returns a pointer which can subsequently be used by
+.Fn LibAliasRedirectDelete .
+If
+.Dv NULL
+is returned, then the function call did not complete successfully.
+.Ed
+.Sh FRAGMENT HANDLING
+The functions in this section are used to deal with incoming fragments.
+.Pp
+Outgoing fragments are handled within
+.Fn LibAliasOut
+by changing the address according to any applicable mapping set by
+.Fn LibAliasRedirectAddr ,
+or the default aliasing address set by
+.Fn LibAliasSetAddress .
+.Pp
+Incoming fragments are handled in one of two ways.
+If the header of a fragmented IP packet has already been seen, then all
+subsequent fragments will be re-mapped in the same manner the header
+fragment was.
+Fragments which arrive before the header are saved and then retrieved
+once the header fragment has been resolved.
+.Pp
+.Ft int
+.Fn LibAliasSaveFragment "struct libalias *" "char *ptr"
+.Bd -ragged -offset indent
+When
+.Fn LibAliasIn
+returns
+.Dv PKT_ALIAS_UNRESOLVED_FRAGMENT ,
+this function can be used to save the pointer to the unresolved fragment.
+.Pp
+It is implicitly assumed that
+.Fa ptr
+points to a block of memory allocated by
+.Xr malloc 3 .
+If the fragment is never resolved, the packet aliasing engine will
+automatically free the memory after a timeout period.
+[Eventually this function should be modified so that a callback function
+for freeing memory is passed as an argument.]
+.Pp
+This function returns
+.Dv PKT_ALIAS_OK
+if it was successful and
+.Dv PKT_ALIAS_ERROR
+if there was an error.
+.Ed
+.Pp
+.Ft char *
+.Fn LibAliasGetFragment "struct libalias *" "char *buffer"
+.Bd -ragged -offset indent
+This function can be used to retrieve fragment pointers saved by
+.Fn LibAliasSaveFragment .
+The IP header fragment pointed to by
+.Fa buffer
+is the header fragment indicated when
+.Fn LibAliasIn
+returns
+.Dv PKT_ALIAS_FOUND_HEADER_FRAGMENT .
+Once a fragment pointer is retrieved, it becomes the calling program's
+responsibility to free the dynamically allocated memory for the fragment.
+.Pp
+The
+.Fn LibAliasGetFragment
+function can be called sequentially until there are no more fragments
+available, at which time it returns
+.Dv NULL .
+.Ed
+.Pp
+.Ft void
+.Fn LibAliasFragmentIn "struct libalias *" "char *header" "char *fragment"
+.Bd -ragged -offset indent
+When a fragment is retrieved with
+.Fn LibAliasGetFragment ,
+it can then be de-aliased with a call to
+.Fn LibAliasFragmentIn .
+The
+.Fa header
+argument is the pointer to a header fragment used as a template, and
+.Fa fragment
+is the pointer to the packet to be de-aliased.
+.Ed
+.Sh MISCELLANEOUS FUNCTIONS
+.Ft void
+.Fn LibAliasSetTarget "struct libalias *" "struct in_addr addr"
+.Bd -ragged -offset indent
+When an incoming packet not associated with any pre-existing aliasing link
+arrives at the host machine, it will be sent to the address indicated by a
+call to
+.Fn LibAliasSetTarget .
+.Pp
+If this function is called with an
+.Dv INADDR_NONE
+address argument, then all new incoming packets go to the address set by
+.Fn LibAliasSetAddress .
+.Pp
+If this function is not called, or is called with an
+.Dv INADDR_ANY
+address argument, then all new incoming packets go to the address specified
+in the packet.
+This allows external machines to talk directly to internal machines if they
+can route packets to the machine in question.
+.Ed
+.Pp
+.Ft int
+.Fn LibAliasCheckNewLink "struct libalias *"
+.Bd -ragged -offset indent
+This function returns a non-zero value when a new aliasing link is created.
+In circumstances where incoming traffic is being sequentially sent to
+different local servers, this function can be used to trigger when
+.Fn LibAliasSetTarget
+is called to change the default target address.
+.Ed
+.Pp
+.Ft u_short
+.Fn LibAliasInternetChecksum "struct libalias *" "u_short *buffer" "int nbytes"
+.Bd -ragged -offset indent
+This is a utility function that does not seem to be available elsewhere and
+is included as a convenience.
+It computes the internet checksum, which is used in both IP and
+protocol-specific headers (TCP, UDP, ICMP).
+.Pp
+The
+.Fa buffer
+argument points to the data block to be checksummed, and
+.Fa nbytes
+is the number of bytes.
+The 16-bit checksum field should be zeroed before computing the checksum.
+.Pp
+Checksums can also be verified by operating on a block of data including
+its checksum.
+If the checksum is valid,
+.Fn LibAliasInternetChecksum
+will return zero.
+.Ed
+.Pp
+.Ft int
+.Fn LibAliasUnaliasOut "struct libalias *" "char *buffer" "int maxpacketsize"
+.Bd -ragged -offset indent
+An outgoing packet, which has already been aliased,
+has its private address/port information restored by this function.
+The IP packet is pointed to by
+.Fa buffer ,
+and
+.Fa maxpacketsize
+is provided for error checking purposes.
+This function can be used if an already-aliased packet needs to have its
+original IP header restored for further processing (e.g.\& logging).
+.Ed
+.Sh AUTHORS
+.An Charles Mott Aq cm@linktel.net ,
+versions 1.0 - 1.8, 2.0 - 2.4.
+.An Eivind Eklund Aq eivind@FreeBSD.org ,
+versions 1.8b, 1.9 and 2.5.
+Added IRC DCC support as well as contributing a number of architectural
+improvements; added the firewall bypass for FTP/IRC DCC.
+.An Erik Salander Aq erik@whistle.com
+added support for PPTP and RTSP.
+.An Junichi Satoh Aq junichi@junichi.org
+added support for RTSP/PNA.
+.An Ruslan Ermilov Aq ru@FreeBSD.org
+added support for PPTP and LSNAT as well as general hacking.
+.An Paolo Pisati Aq piso@FreeBSD.org
+made the library modular, moving support for all
+protocols (except for IP, TCP and UDP) to external modules.
+.Sh ACKNOWLEDGMENTS
+Listed below, in approximate chronological order, are individuals who
+have provided valuable comments and/or debugging assistance.
+.Pp
+.Bd -ragged -offset indent
+.An -split
+.An Gary Roberts
+.An Tom Torrance
+.An Reto Burkhalter
+.An Martin Renters
+.An Brian Somers
+.An Paul Traina
+.An Ari Suutari
+.An Dave Remien
+.An J. Fortes
+.An Andrzej Bialecki
+.An Gordon Burditt
+.Ed
+.Sh CONCEPTUAL BACKGROUND
+This section is intended for those who are planning to modify the source
+code or want to create somewhat esoteric applications using the packet
+aliasing functions.
+.Pp
+The conceptual framework under which the packet aliasing engine operates
+is described here.
+Central to the discussion is the idea of an
+.Em aliasing link
+which describes the relationship for a given packet transaction between
+the local machine, aliased identity and remote machine.
+It is discussed how such links come into existence and are destroyed.
+.Ss ALIASING LINKS
+There is a notion of an
+.Em aliasing link ,
+which is a 7-tuple describing a specific translation:
+.Bd -literal -offset indent
+(local addr, local port, alias addr, alias port,
+ remote addr, remote port, protocol)
+.Ed
+.Pp
+Outgoing packets have the local address and port number replaced with the
+alias address and port number.
+Incoming packets undergo the reverse process.
+The packet aliasing engine attempts to match packets against an internal
+table of aliasing links to determine how to modify a given IP packet.
+Both the IP header and protocol dependent headers are modified as necessary.
+Aliasing links are created and deleted as necessary according to network
+traffic.
+.Pp
+Protocols can be TCP, UDP or even ICMP in certain circumstances.
+(Some types of ICMP packets can be aliased according to sequence or ID
+number which acts as an equivalent port number for identifying how
+individual packets should be handled.)
+.Pp
+Each aliasing link must have a unique combination of the following five
+quantities: alias address/port, remote address/port and protocol.
+This ensures that several machines on a local network can share the
+same aliasing IP address.
+In cases where conflicts might arise, the aliasing port is chosen so that
+uniqueness is maintained.
+.Ss STATIC AND DYNAMIC LINKS
+Aliasing links can either be static or dynamic.
+Static links persist indefinitely and represent fixed rules for translating
+IP packets.
+Dynamic links come into existence for a specific TCP connection or UDP
+transaction or ICMP ECHO sequence.
+For the case of TCP, the connection can be monitored to see when the
+associated aliasing link should be deleted.
+Aliasing links for UDP transactions (and ICMP ECHO and TIMESTAMP requests)
+work on a simple timeout rule.
+When no activity is observed on a dynamic link for a certain amount of time
+it is automatically deleted.
+Timeout rules also apply to TCP connections which do not open or close
+properly.
+.Ss PARTIALLY SPECIFIED ALIASING LINKS
+Aliasing links can be partially specified, meaning that the remote address
+and/or remote port are unknown.
+In this case, when a packet matching the incomplete specification is found,
+a fully specified dynamic link is created.
+If the original partially specified link is dynamic, it will be deleted
+after the fully specified link is created, otherwise it will persist.
+.Pp
+For instance, a partially specified link might be
+.Bd -literal -offset indent
+(192.168.0.4, 23, 204.228.203.215, 8066, 0, 0, tcp)
+.Ed
+.Pp
+The zeros denote unspecified components for the remote address and port.
+If this link were static it would have the effect of redirecting all
+incoming traffic from port 8066 of 204.228.203.215 to port 23 (telnet)
+of machine 192.168.0.4 on the local network.
+Each individual telnet connection would initiate the creation of a distinct
+dynamic link.
+.Ss DYNAMIC LINK CREATION
+In addition to aliasing links, there are also address mappings that can be
+stored within the internal data table of the packet aliasing mechanism.
+.Bd -literal -offset indent
+(local addr, alias addr)
+.Ed
+.Pp
+Address mappings are searched when creating new dynamic links.
+.Pp
+All outgoing packets from the local network automatically create a dynamic
+link if they do not match an already existing fully specified link.
+If an address mapping exists for the outgoing packet, this determines
+the alias address to be used.
+If no mapping exists, then a default address, usually the address of the
+packet aliasing host, is used.
+If necessary, this default address can be changed as often as each individual
+packet arrives.
+.Pp
+The aliasing port number is determined such that the new dynamic link does
+not conflict with any existing links.
+In the default operating mode, the packet aliasing engine attempts to set
+the aliasing port equal to the local port number.
+If this results in a conflict, then port numbers are randomly chosen until
+a unique aliasing link can be established.
+In an alternate operating mode, the first choice of an aliasing port is also
+random and unrelated to the local port number.
+.Sh MODULAR ARCHITECTURE (AND Xr ipfw 4 Sh SUPPORT)
+One of the latest improvements to
+.Nm
+was to make its support
+for new protocols independent from the rest of the library, giving it
+the ability to load/unload support for new protocols at run-time.
+To achieve this feature, all the code for protocol handling was moved
+to a series of modules outside of the main library.
+These modules are compiled from the same sources but work in
+different ways, depending on whether they are compiled to work inside a kernel
+or as part of the userland library.
+.Ss LIBALIAS MODULES IN KERNEL LAND
+When compiled for the kernel,
+.Nm
+modules are plain KLDs recognizable with the
+.Pa alias_
+prefix.
+.Pp
+To add support for a new protocol, load the corresponding module.
+For example:
+.Pp
+.Dl "kldload alias_ftp"
+.Pp
+When support for a protocol is no longer needed, its module can be unloaded:
+.Pp
+.Dl "kldunload alias_ftp"
+.Ss LIBALIAS MODULES IN USERLAND
+Due to the differences between kernel and userland (no KLD mechanism,
+many different address spaces, etc.), we had to change a bit how to
+handle module loading/tracking/unloading in userland.
+.Pp
+While compiled for a userland
+.Nm ,
+all the modules are plain libraries, residing in
+.Pa /usr/lib ,
+and recognizable with the
+.Pa libalias_
+prefix.
+.Pp
+There is a configuration file,
+.Pa /etc/libalias.conf ,
+with the following contents (by default):
+.Bd -literal -offset indent
+/usr/lib/libalias_cuseeme.so
+/usr/lib/libalias_ftp.so
+/usr/lib/libalias_irc.so
+/usr/lib/libalias_nbt.so
+/usr/lib/libalias_pptp.so
+/usr/lib/libalias_skinny.so
+/usr/lib/libalias_smedia.so
+.Ed
+.Pp
+This file contains the paths to the modules that
+.Nm
+will load.
+To load/unload a new module, just add its path to
+.Pa libalias.conf
+and call
+.Fn LibAliasRefreshModules
+from the program.
+In case the application provides a
+.Dv SIGHUP
+signal handler, add a call to
+.Fn LibAliasRefreshModules
+inside the handler, and everytime you want to refresh the loaded modules,
+send it the
+.Dv SIGHUP
+signal:
+.Pp
+.Dl "kill -HUP <process_pid>"
+.Ss MODULAR ARCHITECURE: HOW IT WORKS
+The modular architecture of
+.Nm
+works similar whether it is running inside the
+kernel or in userland.
+From
+.Pa alias_mod.c :
+.Bd -literal
+/* Protocol and userland module handlers chains. */
+LIST_HEAD(handler_chain, proto_handler) handler_chain ...
+\&...
+SLIST_HEAD(dll_chain, dll) dll_chain ...
+.Ed
+.Pp
+.Va handler_chain
+keep tracks of all the protocol handlers loaded, while
+.Va ddl_chain
+takes care of userland modules loaded.
+.Pp
+.Va handler_chain
+is composed of
+.Vt "struct proto_handler"
+entries:
+.Bd -literal
+struct proto_handler {
+	u_int pri;
+	int16_t dir;
+	uint8_t proto;
+	int (*fingerprint)(struct libalias *la,
+		 struct ip *pip, struct alias_data *ah);
+	int (*protohandler)(struct libalias *la,
+		 struct ip *pip, struct alias_data *ah);
+	LIST_ENTRY(proto_handler) entries;
+};
+.Ed
+.Pp
+where:
+.Bl -inset
+.It Va pri
+is the priority assigned to a protocol handler, lower
+is better.
+.It Va dir
+is the direction of packets: ingoing or outgoing.
+.It Va proto
+says at which protocol this packet belongs: IP, TCP or UDP.
+.It Va fingerprint
+points to the fingerprint function while protohandler points
+to the protocol handler function.
+.El
+.Pp
+The
+.Va fingerprint
+function has the double of scope of checking if the
+incoming packet is found and if it belongs to any categories that this
+module can handle.
+.Pp
+The
+.Va protohandler
+function actually manipulates
+the packet to make
+.Nm
+correctly NAT it.
+.Pp
+When a packet enters
+.Nm ,
+if it meets a module hook,
+.Va handler_chain
+is searched to see if there is an handler that matches
+this type of a packet (it checks protocol and direction of packet), then if
+more than one handler is found, it starts with the module with
+the lowest priority number: it calls the
+.Va fingerprint
+function and interprets the result.
+.Pp
+If the result value is equal to 0 then it calls the protocol handler
+of this handler and returns.
+Otherwise, it proceeds to the next eligible module until the
+.Va handler_chain
+is exhausted.
+.Pp
+Inside
+.Nm ,
+the module hook looks like this:
+.Bd -literal -offset indent
+struct alias_data ad = {
+	lnk,
+	&original_address,
+	&alias_address,
+	&alias_port,
+	&ud->uh_sport,          /* original source port */
+	&ud->uh_dport,		/* original dest port */
+	256                     /* maxpacketsize */
+};
+
+\&...
+
+/* walk out chain */
+err = find_handler(IN, UDP, la, pip, &ad);
+.Ed
+.Pp
+All data useful to a module are gathered together in an
+.Vt alias_data
+structure, then
+.Fn find_handler
+is called.
+The
+.Fn find_handler
+function is responsible for walking out the handler
+chain, it receives as input parameters:
+.Bl -tag -width indent
+.It Fa IN
+direction
+.It Fa UDP
+working protocol
+.It Fa la
+pointer to this instance of libalias
+.It Fa pip
+pointer to a
+.Vt "struct ip"
+.It Fa ad
+pointer to
+.Vt "struct alias_data"
+(see above)
+.El
+.Pp
+In this case,
+.Fn find_handler
+will search only for modules registered for
+supporting INcoming UDP packets.
+.Pp
+As was mentioned earlier,
+.Nm
+in userland is a bit different, cause
+care has to be taken of module handling too (avoiding duplicate load of
+module, avoiding module with same name, etc.) so
+.Va dll_chain
+was introduced.
+.Pp
+.Va dll_chain
+contains a list of all userland
+.Nm
+modules loaded.
+.Pp
+When an application calls
+.Fn LibAliasRefreshModules ,
+.Nm
+first unloads all the loaded modules, then reloads all the modules listed in
+.Pa /etc/libalias.conf :
+for every module loaded, a new entry to
+.Va dll_chain
+is added.
+.Pp
+.Va dll_chain
+is composed of
+.Vt "struct dll"
+entries:
+.Bd -literal
+struct dll {
+	/* name of module */
+	char            name[DLL_LEN];
+	/*
+	 * ptr to shared obj obtained through
+	 * dlopen() - use this ptr to get access
+	 * to any symbols from a loaded module
+	 * via dlsym()
+	 */
+	void            *handle;
+	struct dll      *next;
+};
+.Ed
+.Bl -inset
+.It Va name
+is the name of the module
+.It Va handle
+is a pointer to the module obtained through
+.Xr dlopen 3
+.El
+Whenever a module is loaded in userland, an entry is added to
+.Va dll_chain ,
+then every protocol handler present in that module
+is resolved and registered in
+.Va handler_chain .
+.Ss HOW TO WRITE A MODULE FOR LIBALIAS
+There is a module (called
+.Pa alias_dummy.[ch] )
+in
+.Nm
+that can be used as a skeleton for future work, here we analyse some parts of that
+module.
+From
+.Pa alias_dummy.c :
+.Bd -literal
+struct proto_handler handlers [] = {{666, IN|OUT, UDP|TCP,
+				    &fingerprint, &protohandler}};
+.Ed
+.Pp
+The variable
+.Va handlers
+is the
+.Dq "most important thing"
+in a module
+cause it describes the handlers present and lets the outside world use
+it in an opaque way.
+.Pp
+It must ALWAYS be present in every module, and it MUST retain
+the name
+.Va handlers ,
+otherwise attempting to load a module in userland will fail and
+complain about missing symbols: for more information about module
+load/unload, please refer to
+.Fn LibAliasRefreshModules ,
+.Fn LibAliasLoadModule
+and
+.Fn LibAliasUnloadModule
+in
+.Pa alias.c .
+.Pp
+.Va handlers
+contains all the
+.Vt proto_handler
+structures present in a module.
+.Bd -literal
+static int
+mod_handler(module_t mod, int type, void *data)
+{
+	int error;
+
+	switch (type) {
+	case MOD_LOAD:
+		error = 0;
+		attach_handlers(handlers);
+		break;
+	case MOD_UNLOAD:
+		error = 0;
+		detach_handlers(handlers;
+		break;
+	default:
+		error = EINVAL;
+	}
+	return (error);
+}
+.Ed
+When running as KLD,
+.Fn mod_handler
+register/deregister the module using
+.Fn attach_handlers
+and
+.Fn detach_handlers ,
+respectively.
+.Pp
+Every module must contain at least 2 functions: one fingerprint
+function and a protocol handler function.
+.Bd -literal
+#ifdef _KERNEL
+static
+#endif
+int
+fingerprint(struct libalias *la, struct ip *pip, struct alias_data *ah)
+{
+
+\&...
+}
+
+#ifdef _KERNEL
+static
+#endif
+int
+protohandler(struct libalias *la, struct ip *pip,
+             struct alias_data *ah)
+{
+
+\&...
+}
+.Ed
+and they must accept exactly these input parameters.
+.Ss PATCHING AN APPLICATION FOR USERLAND LIBALIAS MODULES
+To add module support into an application that uses
+.Nm ,
+the following simple steps can be followed.
+.Bl -enum
+.It
+Find the main file of an application
+(let us call it
+.Pa main.c ) .
+.It
+Add this to the header section of
+.Pa main.c ,
+if not already present:
+.Pp
+.Dl "#include <signal.h>"
+.Pp
+and this just after the header section:
+.Pp
+.Dl "static void signal_handler(int);"
+.It
+Add the following line to the init function of an application or,
+if it does not have any init function, put it in
+.Fn main :
+.Pp
+.Dl "signal(SIGHUP, signal_handler);"
+.Pp
+and place the
+.Fn signal_handler
+function somewhere in
+.Pa main.c :
+.Bd -literal -offset indent
+static void
+signal_handler(int sig)
+{
+
+	LibAliasRefreshModules();
+}
+.Ed
+.Pp
+Otherwise, if an application already traps the
+.Dv SIGHUP
+signal, just add a call to
+.Fn LibAliasRefreshModules
+in the signal handler function.
+.El
+For example, to patch
+.Xr natd 8
+to use
+.Nm
+modules, just add the following line to
+.Fn RefreshAddr "int sig __unused" :
+.Pp
+.Dl "LibAliasRefreshModules()"
+.Pp
+recompile and you are done.
+.Ss LOGGING SUPPORT IN KERNEL LAND
+When working as KLD,
+.Nm
+now has log support that
+happens on a buffer allocated inside
+.Vt "struct libalias"
+(from
+.Pa alias_local.h ) :
+.Bd -literal
+struct libalias {
+       ...
+
+	/* log descriptor        */
+#ifdef	KERNEL_LOG
+	char           *logDesc;        /*
+					 * ptr to an auto-malloced
+					 * memory buffer when libalias
+					 * works as kld
+					 */
+#else
+	FILE           *logDesc;	/*
+					 * ptr to /var/log/alias.log
+					 * when libalias runs as a
+					 * userland lib
+					 */
+#endif
+
+	...
+}
+.Ed
+so all applications using
+.Nm
+will be able to handle their
+own logs, if they want, accessing
+.Va logDesc .
+Moreover, every change to a log buffer is automatically added to
+.Xr syslog 3
+with the
+.Dv LOG_SECURITY
+facility and the
+.Dv LOG_INFO
+level.
