summaryrefslogtreecommitdiffstats
path: root/src/VBox/HostDrivers/VBoxNetAdp
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 16:49:04 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 16:49:04 +0000
commit16f504a9dca3fe3b70568f67b7d41241ae485288 (patch)
treec60f36ada0496ba928b7161059ba5ab1ab224f9d /src/VBox/HostDrivers/VBoxNetAdp
parentInitial commit. (diff)
downloadvirtualbox-16f504a9dca3fe3b70568f67b7d41241ae485288.tar.xz
virtualbox-16f504a9dca3fe3b70568f67b7d41241ae485288.zip
Adding upstream version 7.0.6-dfsg.upstream/7.0.6-dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/HostDrivers/VBoxNetAdp')
-rw-r--r--src/VBox/HostDrivers/VBoxNetAdp/Makefile.kmk228
-rw-r--r--src/VBox/HostDrivers/VBoxNetAdp/VBoxNetAdp.c238
-rw-r--r--src/VBox/HostDrivers/VBoxNetAdp/VBoxNetAdpInternal.h203
-rw-r--r--src/VBox/HostDrivers/VBoxNetAdp/darwin/Info.plist26
-rw-r--r--src/VBox/HostDrivers/VBoxNetAdp/darwin/Makefile.kup0
-rw-r--r--src/VBox/HostDrivers/VBoxNetAdp/darwin/VBoxNetAdp-darwin.cpp529
-rwxr-xr-xsrc/VBox/HostDrivers/VBoxNetAdp/darwin/loadnetadp.sh133
-rw-r--r--src/VBox/HostDrivers/VBoxNetAdp/freebsd/Makefile54
-rw-r--r--src/VBox/HostDrivers/VBoxNetAdp/freebsd/VBoxNetAdp-freebsd.c339
-rwxr-xr-xsrc/VBox/HostDrivers/VBoxNetAdp/freebsd/files_vboxnetadp94
-rw-r--r--src/VBox/HostDrivers/VBoxNetAdp/linux/Makefile78
-rw-r--r--src/VBox/HostDrivers/VBoxNetAdp/linux/Makefile.kup0
-rw-r--r--src/VBox/HostDrivers/VBoxNetAdp/linux/VBoxNetAdp-linux.c583
-rwxr-xr-xsrc/VBox/HostDrivers/VBoxNetAdp/linux/files_vboxnetadp112
-rw-r--r--src/VBox/HostDrivers/VBoxNetAdp/solaris/VBoxNetAdp-solaris.c581
-rw-r--r--src/VBox/HostDrivers/VBoxNetAdp/solaris/hostname.vboxnet01
-rw-r--r--src/VBox/HostDrivers/VBoxNetAdp/solaris/vboxnet.conf43
-rw-r--r--src/VBox/HostDrivers/VBoxNetAdp/win/Makefile.kup0
-rw-r--r--src/VBox/HostDrivers/VBoxNetAdp/win/VBoxNetAdp-win.cpp1888
-rw-r--r--src/VBox/HostDrivers/VBoxNetAdp/win/VBoxNetAdp-win.h71
-rw-r--r--src/VBox/HostDrivers/VBoxNetAdp/win/VBoxNetAdp-win.rc72
-rw-r--r--src/VBox/HostDrivers/VBoxNetAdp/win/VBoxNetAdp6.inf107
22 files changed, 5380 insertions, 0 deletions
diff --git a/src/VBox/HostDrivers/VBoxNetAdp/Makefile.kmk b/src/VBox/HostDrivers/VBoxNetAdp/Makefile.kmk
new file mode 100644
index 00000000..74f5a414
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetAdp/Makefile.kmk
@@ -0,0 +1,228 @@
+# $Id: Makefile.kmk $
+## @file
+# Sub-Makefile for the Network Adapter Driver (VBoxNetAdp).
+#
+
+#
+# Copyright (C) 2009-2022 Oracle and/or its affiliates.
+#
+# This file is part of VirtualBox base platform packages, as
+# available from https://www.virtualbox.org.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation, in version 3 of the
+# License.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses>.
+#
+# The contents of this file may alternatively be used under the terms
+# of the Common Development and Distribution License Version 1.0
+# (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+# in the VirtualBox distribution, in which case the provisions of the
+# CDDL are applicable instead of those of the GPL.
+#
+# You may elect to license modified versions of this file under the
+# terms and conditions of either the GPL or the CDDL or both.
+#
+# SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+#
+
+SUB_DEPTH = ../../../..
+include $(KBUILD_PATH)/subheader.kmk
+
+if1of ($(KBUILD_TARGET), solaris darwin freebsd)
+ #
+ # VBoxNetAdp - Virtual Network Adapter
+ # Note! On Solaris the name has to be <= 8 chars long.
+ #
+ ifdef VBOX_WITH_VBOXDRV
+ SYSMODS += VBoxNetAdp
+ VBoxNetAdp_TEMPLATE = VBOXR0DRV
+ VBoxNetAdp_INST = $(INST_VBOXNETADP)$(if $(eq $(KBUILD_TARGET),darwin),Contents/MacOS/)
+ VBoxNetAdp_DEBUG_INST.darwin= $(patsubst %/,%,$(INST_VBOXNETADP))
+ VBoxNetAdp_NAME.solaris = vboxnet
+ VBoxNetAdp_NAME.freebsd = vboxnetadp
+ VBoxNetAdp_DEPS.solaris += $(VBOX_SVN_REV_KMK)
+ VBoxNetAdp_DEFS = IN_RT_R0 VBOX_SVN_REV=$(VBOX_SVN_REV) IN_SUP_STATIC
+ #VBoxNetAdp_LDFLAGS.darwin = -v -Wl,-whyload -Wl,-v -Wl,-whatsloaded
+ VBoxNetAdp_LDFLAGS.solaris += -N misc/gld -N drv/vboxdrv
+ VBoxNetAdp_INCS = \
+ .
+ VBoxNetAdp_SOURCES.darwin = \
+ darwin/VBoxNetAdp-darwin.cpp \
+ VBoxNetAdp.c
+ VBoxNetAdp_SOURCES.solaris = \
+ solaris/VBoxNetAdp-solaris.c
+ VBoxNetAdp_SOURCES.freebsd = \
+ freebsd/VBoxNetAdp-freebsd.c \
+ VBoxNetAdp.c
+ VBoxNetAdp_SOURCES =
+ #VBoxNetAdp_SOURCES = \
+ # VBoxNetAdp.c
+ VBoxNetAdp_LIBS += \
+ $(PATH_STAGE_LIB)/SUPR0IdcClient$(VBOX_SUFF_LIB)
+ endif
+endif
+
+#
+# Darwin extras.
+#
+if "$(KBUILD_TARGET)" == "darwin" && defined(VBOX_WITH_VBOXDRV)
+ INSTALLS += VBoxNetAdp.kext
+ VBoxNetAdp.kext_INST = $(INST_VBOXNETADP)Contents/
+ VBoxNetAdp.kext_SOURCES = $(VBoxNetAdp.kext_0_OUTDIR)/Contents/Info.plist
+ VBoxNetAdp.kext_CLEAN = $(VBoxNetAdp.kext_0_OUTDIR)/Contents/Info.plist
+ VBoxNetAdp.kext_BLDDIRS = $(VBoxNetAdp.kext_0_OUTDIR)/Contents/
+
+$$(VBoxNetAdp.kext_0_OUTDIR)/Contents/Info.plist: $(PATH_SUB_CURRENT)/darwin/Info.plist $(VBOX_VERSION_MK) | $$(dir $$@)
+ $(call MSG_GENERATE,VBoxNetAdp,$@,$<)
+ $(QUIET)$(RM) -f $@
+ $(QUIET)$(SED) \
+ -e 's+@VBOX_VERSION_STRING@+$(VBOX_VERSION_STRING)+g' \
+ -e 's+@VBOX_VERSION_MAJOR@+$(VBOX_VERSION_MAJOR)+g' \
+ -e 's+@VBOX_VERSION_MINOR@+$(VBOX_VERSION_MINOR)+g' \
+ -e 's+@VBOX_VERSION_BUILD@+$(VBOX_VERSION_BUILD)+g' \
+ -e 's+@VBOX_VENDOR@+$(VBOX_VENDOR)+g' \
+ -e 's+@VBOX_PRODUCT@+$(VBOX_PRODUCT)+g' \
+ -e 's+@VBOX_C_YEAR@+$(VBOX_C_YEAR)+g' \
+ --output $@ \
+ $<
+
+ $(evalcall2 VBOX_TEST_SIGN_KEXT,VBoxNetAdp)
+
+ INSTALLS.darwin += Scripts-darwin-adp
+ Scripts-darwin-adp_INST = $(INST_DIST)
+ Scripts-darwin-adp_EXEC_SOURCES = \
+ darwin/loadnetadp.sh
+endif # darwin && host-drivers
+
+ifeq ($(KBUILD_TARGET),win)
+ #
+ # VBoxNetAdp6.sys - The VirtualBox Adapter miniport driver.
+ #
+ SYSMODS.win += VBoxNetAdp6
+ VBoxNetAdp6_TEMPLATE = VBOXR0DRV
+ if defined(VBOX_SIGNING_MODE)
+ VBoxNetAdp6_INSTTYPE.win = none
+ VBoxNetAdp6_DEBUG_INSTTYPE.win = both
+ endif
+ VBoxNetAdp6_DEFS = IN_RT_R0 IN_SUP_STATIC
+ VBoxNetAdp6_INCS := $(PATH_SUB_CURRENT)
+ VBoxNetAdp6_SDKS = ReorderCompilerIncs $(VBOX_WINDDK_WLH) $(VBOX_WINPSDK_INCS)
+ VBoxNetAdp6_SOURCES = \
+ win/VBoxNetAdp-win.cpp \
+ win/VBoxNetAdp-win.rc
+ VBoxNetAdp6_DEFS += NDIS_MINIPORT_DRIVER NDIS_WDM=1 BINARY_COMPATIBLE=0
+ VBoxNetAdp6_DEFS += NDIS60_MINIPORT=1 NDIS60=1
+ VBoxNetAdp6_LDFLAGS.win.x86 = -Entry:DriverEntry@8
+ VBoxNetAdp6_LDFLAGS.win.amd64 = -Entry:DriverEntry
+ VBoxNetAdp6_LIBS.win = \
+ $(PATH_SDK_$(VBOX_WINDDK)_LIB)/ntoskrnl.lib \
+ $(PATH_SDK_$(VBOX_WINDDK)_LIB)/hal.lib \
+ $(PATH_SDK_$(VBOX_WINDDK)_LIB)/ndis.lib \
+ $(PATH_STAGE_LIB)/RuntimeR0Drv$(VBOX_SUFF_LIB)
+ VBoxNetAdp6_LIBS = \
+ $(PATH_STAGE_LIB)/SUPR0IdcClient$(VBOX_SUFF_LIB)
+
+
+ INSTALLS.win += VBoxNetAdp6-inf
+ VBoxNetAdp6-inf_TEMPLATE = VBoxR0DrvInfCat
+ VBoxNetAdp6-inf_SOURCES = \
+ $(PATH_TARGET)/VBoxNetAdp6Cat.dir/VBoxNetAdp6.inf
+ VBoxNetAdp6-inf_CLEAN = $(VBoxNetAdp6-inf_SOURCES)
+ VBoxNetAdp6-inf_BLDDIRS = $(PATH_TARGET)/VBoxNetAdp6Cat.dir
+
+$(PATH_TARGET)/VBoxNetAdp6Cat.dir/VBoxNetAdp6.inf: $(PATH_SUB_CURRENT)/win/VBoxNetAdp6.inf $(MAKEFILE_CURRENT) | $$(dir $$@)
+ $(call MSG_GENERATE,VBoxNetAdp6-inf,$@,$<)
+ $(call VBOX_EDIT_INF_FN,$<,$@)
+
+ ifdef VBOX_SIGNING_MODE
+VBoxNetAdp6-inf_SOURCES += \
+ $(PATH_TARGET)/VBoxNetAdp6Cat.dir/VBoxNetAdp6.sys \
+ $(PATH_TARGET)/VBoxNetAdp6Cat.dir/VBoxNetAdp6.cat \
+ $(PATH_TARGET)/VBoxNetAdp6Cat.dir/VBoxNetAdp6.cat=>VBoxNetAdp6-PreW10.cat
+
+$(PATH_TARGET)/VBoxNetAdp6Cat.dir/VBoxNetAdp6.sys: $$(VBoxNetAdp6_1_TARGET) | $$(dir $$@)
+ $(INSTALL) -m 644 $< $(@D)
+
+$(PATH_TARGET)/VBoxNetAdp6Cat.dir/VBoxNetAdp6.cat: \
+ $(PATH_TARGET)/VBoxNetAdp6Cat.dir/VBoxNetAdp6.sys \
+ $(PATH_TARGET)/VBoxNetAdp6Cat.dir/VBoxNetAdp6.inf
+ $(call MSG_TOOL,Inf2Cat,VBoxNetFlt-inf,$@,$<)
+ $(call VBOX_MAKE_CAT_FN, $(@D),$@)
+
+ endif # ifdef VBOX_SIGNING_MODE
+
+endif #ifeq ($(KBUILD_TARGET), win)
+
+ifeq ($(KBUILD_TARGET),linux)
+ #
+ # Install source files for compilation on Linux.
+ # files_vboxnetadp defines VBOX_VBOXNETADP_SOURCES.
+ #
+ INSTALLS += VBoxNetAdp-src
+ include $(PATH_SUB_CURRENT)/linux/files_vboxnetadp
+ VBoxNetAdp-src_INST = bin/src/vboxnetadp/
+ VBoxNetAdp-src_SOURCES = \
+ $(subst $(DQUOTE),,$(VBOX_VBOXNETADP_SOURCES)) \
+ $(VBoxNetAdp-src_0_OUTDIR)/Makefile
+ VBoxNetAdp-src_CLEAN = \
+ $(VBoxNetAdp-src_0_OUTDIR)/Makefile \
+ $(PATH_TARGET)/VBoxNetAdp-src-1.dep \
+
+ # Scripts needed for building the kernel modules
+ includedep $(PATH_TARGET)/VBoxNetAdp-src-1.dep
+$$(VBoxNetAdp-src_0_OUTDIR)/Makefile: \
+ $(PATH_SUB_CURRENT)/linux/Makefile \
+ $$(if $$(eq $$(VBoxNetAdp/linux/Makefile_VBOX_HARDENED),$$(VBOX_WITH_HARDENING)),,FORCE) \
+ | $$(dir $$@)
+ $(QUIET)$(RM) -f -- $@
+ ifndef VBOX_WITH_HARDENING
+ $(QUIET)$(SED) -e "s;VBOX_WITH_HARDENING;;g" --output $@ $<
+ else
+ $(QUIET)$(CP) -f $< $@
+ endif
+ %$(QUIET2)$(APPEND) -t '$(PATH_TARGET)/VBoxNetAdp-src-1.dep' 'VBoxNetAdp/linux/Makefile_VBOX_HARDENED=$(VBOX_WITH_HARDENING)'
+
+ #
+ # Build test for the linux host kernel modules.
+ #
+ $(evalcall2 VBOX_LINUX_KMOD_TEST_BUILD_RULE_FN,VBoxNetAdp-src,vboxdrv-src,)
+endif # linux
+
+ifeq ($(KBUILD_TARGET),freebsd)
+ #
+ # Install source files for compilation on FreeBSD.
+ # files_vboxnetadp defines VBOX_VBOXNETADP_SOURCES.
+ #
+ INSTALLS += VBoxNetAdp-src
+ include $(PATH_SUB_CURRENT)/freebsd/files_vboxnetadp
+ VBoxNetAdp-src_INST = bin/src/vboxnetadp/
+ VBoxNetAdp-src_SOURCES = \
+ $(subst $(DQUOTE),,$(VBOX_VBOXNETADP_SOURCES)) \
+ $(VBoxNetAdp-src_0_OUTDIR)/Makefile
+ VBoxNetAdp-src_CLEAN = \
+ $(VBoxNetAdp-src_0_OUTDIR)/Makefile \
+
+$$(VBoxNetAdp-src_0_OUTDIR)/Makefile: \
+ $(PATH_SUB_CURRENT)/freebsd/Makefile \
+ $$(if $$(eq $$(VBoxNetAdp/freebsd/Makefile_VBOX_HARDENED),$$(VBOX_WITH_HARDENING)),,FORCE) \
+ | $$(dir $$@)
+ $(QUIET)$(RM) -f -- $@
+ ifndef VBOX_WITH_HARDENING
+ $(QUIET)$(SED) -e "s;VBOX_WITH_HARDENING;;g" --output $@ $<
+ else
+ $(QUIET)$(CP) -f $< $@
+ endif
+
+endif # freebsd
+
+include $(FILE_KBUILD_SUB_FOOTER)
+
diff --git a/src/VBox/HostDrivers/VBoxNetAdp/VBoxNetAdp.c b/src/VBox/HostDrivers/VBoxNetAdp/VBoxNetAdp.c
new file mode 100644
index 00000000..306a5775
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetAdp/VBoxNetAdp.c
@@ -0,0 +1,238 @@
+/* $Id: VBoxNetAdp.c $ */
+/** @file
+ * VBoxNetAdp - Virtual Network Adapter Driver (Host), Common Code.
+ */
+
+/*
+ * Copyright (C) 2008-2022 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+/** @page pg_netadp VBoxNetAdp - Network Adapter
+ *
+ * This is a kernel module that creates a virtual interface that can be attached
+ * to an internal network.
+ *
+ * In the big picture we're one of the three trunk interface on the internal
+ * network, the one named "TAP Interface": @image html Networking_Overview.gif
+ *
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_NET_ADP_DRV
+#include "VBoxNetAdpInternal.h"
+
+#include <VBox/log.h>
+#include <VBox/err.h>
+#include <iprt/string.h>
+
+
+VBOXNETADP g_aAdapters[VBOXNETADP_MAX_INSTANCES];
+static uint8_t g_aUnits[VBOXNETADP_MAX_UNITS/8];
+
+
+DECLINLINE(int) vboxNetAdpGetUnitByName(const char *pcszName)
+{
+ uint32_t iUnit = RTStrToUInt32(pcszName + sizeof(VBOXNETADP_NAME) - 1);
+ bool fOld;
+
+ if (iUnit >= VBOXNETADP_MAX_UNITS)
+ return -1;
+
+ fOld = ASMAtomicBitTestAndSet(g_aUnits, iUnit);
+ return fOld ? -1 : (int)iUnit;
+}
+
+DECLINLINE(int) vboxNetAdpGetNextAvailableUnit(void)
+{
+ bool fOld;
+ int iUnit;
+ /* There is absolutely no chance that all units are taken */
+ do {
+ iUnit = ASMBitFirstClear(g_aUnits, VBOXNETADP_MAX_UNITS);
+ if (iUnit < 0)
+ break;
+ fOld = ASMAtomicBitTestAndSet(g_aUnits, iUnit);
+ } while (fOld);
+
+ return iUnit;
+}
+
+DECLINLINE(void) vboxNetAdpReleaseUnit(int iUnit)
+{
+ bool fSet = ASMAtomicBitTestAndClear(g_aUnits, iUnit);
+ NOREF(fSet);
+ Assert(fSet);
+}
+
+/**
+ * Generate a suitable MAC address.
+ *
+ * @param pThis The instance.
+ * @param pMac Where to return the MAC address.
+ */
+DECLHIDDEN(void) vboxNetAdpComposeMACAddress(PVBOXNETADP pThis, PRTMAC pMac)
+{
+ /* Use a locally administered version of the OUI we use for the guest NICs. */
+ pMac->au8[0] = 0x08 | 2;
+ pMac->au8[1] = 0x00;
+ pMac->au8[2] = 0x27;
+
+ pMac->au8[3] = 0; /* pThis->iUnit >> 16; */
+ pMac->au8[4] = 0; /* pThis->iUnit >> 8; */
+ pMac->au8[5] = pThis->iUnit;
+}
+
+int vboxNetAdpCreate(PVBOXNETADP *ppNew, const char *pcszName)
+{
+ int rc;
+ unsigned i;
+ for (i = 0; i < RT_ELEMENTS(g_aAdapters); i++)
+ {
+ PVBOXNETADP pThis = &g_aAdapters[i];
+
+ if (ASMAtomicCmpXchgU32((uint32_t volatile *)&pThis->enmState, kVBoxNetAdpState_Transitional, kVBoxNetAdpState_Invalid))
+ {
+ RTMAC Mac;
+ /* Found an empty slot -- use it. */
+ Log(("vboxNetAdpCreate: found empty slot: %d\n", i));
+ if (pcszName)
+ {
+ Log(("vboxNetAdpCreate: using name: %s\n", pcszName));
+ pThis->iUnit = vboxNetAdpGetUnitByName(pcszName);
+ strncpy(pThis->szName, pcszName, sizeof(pThis->szName) - 1);
+ pThis->szName[sizeof(pThis->szName) - 1] = '\0';
+ }
+ else
+ {
+ pThis->iUnit = vboxNetAdpGetNextAvailableUnit();
+ pThis->szName[0] = '\0';
+ }
+ if (pThis->iUnit < 0)
+ rc = VERR_INVALID_PARAMETER;
+ else
+ {
+ vboxNetAdpComposeMACAddress(pThis, &Mac);
+ rc = vboxNetAdpOsCreate(pThis, &Mac);
+ Log(("vboxNetAdpCreate: pThis=%p pThis->iUnit=%d, pThis->szName=%s\n",
+ pThis, pThis->iUnit, pThis->szName));
+ }
+ if (RT_SUCCESS(rc))
+ {
+ *ppNew = pThis;
+ ASMAtomicWriteU32((uint32_t volatile *)&pThis->enmState, kVBoxNetAdpState_Active);
+ Log2(("VBoxNetAdpCreate: Created %s\n", g_aAdapters[i].szName));
+ }
+ else
+ {
+ ASMAtomicWriteU32((uint32_t volatile *)&pThis->enmState, kVBoxNetAdpState_Invalid);
+ Log(("vboxNetAdpCreate: vboxNetAdpOsCreate failed with '%Rrc'.\n", rc));
+ }
+ for (i = 0; i < RT_ELEMENTS(g_aAdapters); i++)
+ Log2(("VBoxNetAdpCreate: Scanning entry: state=%d unit=%d name=%s\n",
+ g_aAdapters[i].enmState, g_aAdapters[i].iUnit, g_aAdapters[i].szName));
+ return rc;
+ }
+ }
+ Log(("vboxNetAdpCreate: no empty slots!\n"));
+
+ /* All slots in adapter array are busy. */
+ return VERR_OUT_OF_RESOURCES;
+}
+
+int vboxNetAdpDestroy(PVBOXNETADP pThis)
+{
+ int rc = VINF_SUCCESS;
+
+ if (!ASMAtomicCmpXchgU32((uint32_t volatile *)&pThis->enmState, kVBoxNetAdpState_Transitional, kVBoxNetAdpState_Active))
+ return VERR_INTNET_FLT_IF_BUSY;
+
+ Assert(pThis->iUnit >= 0 && pThis->iUnit < VBOXNETADP_MAX_UNITS);
+ vboxNetAdpOsDestroy(pThis);
+ vboxNetAdpReleaseUnit(pThis->iUnit);
+ pThis->iUnit = -1;
+ pThis->szName[0] = '\0';
+
+ ASMAtomicWriteU32((uint32_t volatile *)&pThis->enmState, kVBoxNetAdpState_Invalid);
+
+ return rc;
+}
+
+int vboxNetAdpInit(void)
+{
+ unsigned i;
+ /*
+ * Init common members and call OS-specific init.
+ */
+ memset(g_aUnits, 0, sizeof(g_aUnits));
+ memset(g_aAdapters, 0, sizeof(g_aAdapters));
+ LogFlow(("vboxnetadp: max host-only interfaces supported: %d (%d bytes)\n",
+ VBOXNETADP_MAX_INSTANCES, sizeof(g_aAdapters)));
+ for (i = 0; i < RT_ELEMENTS(g_aAdapters); i++)
+ {
+ g_aAdapters[i].enmState = kVBoxNetAdpState_Invalid;
+ g_aAdapters[i].iUnit = -1;
+ vboxNetAdpOsInit(&g_aAdapters[i]);
+ }
+
+ return VINF_SUCCESS;
+}
+
+/**
+ * Finds an adapter by its name.
+ *
+ * @returns Pointer to the instance by the given name. NULL if not found.
+ * @param pszName The name of the instance.
+ */
+PVBOXNETADP vboxNetAdpFindByName(const char *pszName)
+{
+ unsigned i;
+
+ for (i = 0; i < RT_ELEMENTS(g_aAdapters); i++)
+ {
+ PVBOXNETADP pThis = &g_aAdapters[i];
+ Log2(("VBoxNetAdp: Scanning entry: state=%d name=%s\n", pThis->enmState, pThis->szName));
+ if ( strcmp(pThis->szName, pszName) == 0
+ && ASMAtomicReadU32((uint32_t volatile *)&pThis->enmState) == kVBoxNetAdpState_Active)
+ return pThis;
+ }
+ return NULL;
+}
+
+void vboxNetAdpShutdown(void)
+{
+ unsigned i;
+
+ /* Remove virtual adapters */
+ for (i = 0; i < RT_ELEMENTS(g_aAdapters); i++)
+ vboxNetAdpDestroy(&g_aAdapters[i]);
+}
diff --git a/src/VBox/HostDrivers/VBoxNetAdp/VBoxNetAdpInternal.h b/src/VBox/HostDrivers/VBoxNetAdp/VBoxNetAdpInternal.h
new file mode 100644
index 00000000..1f2822d9
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetAdp/VBoxNetAdpInternal.h
@@ -0,0 +1,203 @@
+/* $Id: VBoxNetAdpInternal.h $ */
+/** @file
+ * VBoxNetAdp - Network Filter Driver (Host), Internal Header.
+ */
+
+/*
+ * Copyright (C) 2008-2022 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+#ifndef VBOX_INCLUDED_SRC_VBoxNetAdp_VBoxNetAdpInternal_h
+#define VBOX_INCLUDED_SRC_VBoxNetAdp_VBoxNetAdpInternal_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#include <VBox/sup.h>
+#include <VBox/intnet.h>
+#include <iprt/semaphore.h>
+#include <iprt/assert.h>
+
+
+RT_C_DECLS_BEGIN
+
+/** Pointer to the globals. */
+typedef struct VBOXNETADPGLOBALS *PVBOXNETADPGLOBALS;
+
+#define VBOXNETADP_MAX_INSTANCES 128
+#define VBOXNETADP_MAX_UNITS 128
+#define VBOXNETADP_NAME "vboxnet"
+#define VBOXNETADP_MAX_NAME_LEN 32
+#define VBOXNETADP_MTU 1500
+#if defined(RT_OS_DARWIN)
+# define VBOXNETADP_MAX_FAMILIES 4
+# define VBOXNETADP_DETACH_TIMEOUT 500
+#endif
+
+#define VBOXNETADP_CTL_DEV_NAME "vboxnetctl"
+#define VBOXNETADP_CTL_ADD _IOWR('v', 1, VBOXNETADPREQ)
+#define VBOXNETADP_CTL_REMOVE _IOW('v', 2, VBOXNETADPREQ)
+
+typedef struct VBoxNetAdpReq
+{
+ char szName[VBOXNETADP_MAX_NAME_LEN];
+} VBOXNETADPREQ;
+typedef VBOXNETADPREQ *PVBOXNETADPREQ;
+
+/**
+ * Void entries mark vacant slots in adapter array. Valid entries are busy slots.
+ * As soon as slot is being modified its state changes to transitional.
+ * An entry in transitional state must only be accessed by the thread that
+ * put it to this state.
+ */
+/**
+ * To avoid races on adapter fields we stick to the following rules:
+ * - rewrite: Int net port calls are serialized
+ * - No modifications are allowed on busy adapters (deactivate first)
+ * Refuse to destroy adapter until it gets to available state
+ * - No transfers (thus getting busy) on inactive adapters
+ * - Init sequence: void->available->connected->active
+ 1) Create
+ 2) Connect
+ 3) Activate
+ * - Destruction sequence: active->connected->available->void
+ 1) Deactivate
+ 2) Disconnect
+ 3) Destroy
+*/
+
+enum VBoxNetAdpState
+{
+ kVBoxNetAdpState_Invalid,
+ kVBoxNetAdpState_Transitional,
+ kVBoxNetAdpState_Active,
+ kVBoxNetAdpState_32BitHack = 0x7FFFFFFF
+};
+typedef enum VBoxNetAdpState VBOXNETADPSTATE;
+
+struct VBoxNetAdapter
+{
+ /** Denotes availability of this slot in adapter array. */
+ VBOXNETADPSTATE enmState;
+ /** Corresponds to the digit at the end of device name. */
+ int iUnit;
+
+ union
+ {
+#ifdef VBOXNETADP_OS_SPECFIC
+ struct
+ {
+# if defined(RT_OS_DARWIN)
+ /** @name Darwin instance data.
+ * @{ */
+ /** Event to signal detachment of interface. */
+ RTSEMEVENT hEvtDetached;
+ /** Pointer to Darwin interface structure. */
+ ifnet_t pIface;
+ /** MAC address. */
+ RTMAC Mac;
+ /** @} */
+# elif defined(RT_OS_LINUX)
+ /** @name Darwin instance data.
+ * @{ */
+ /** Pointer to Linux network device structure. */
+ struct net_device *pNetDev;
+ /** @} */
+# elif defined(RT_OS_FREEBSD)
+ /** @name FreeBSD instance data.
+ * @{ */
+ struct ifnet *ifp;
+ /** @} */
+# else
+# error PORTME
+# endif
+ } s;
+#endif
+ /** Union alignment to a pointer. */
+ void *pvAlign;
+ /** Padding. */
+ uint8_t abPadding[64];
+ } u;
+ /** The interface name. */
+ char szName[VBOXNETADP_MAX_NAME_LEN];
+};
+typedef struct VBoxNetAdapter VBOXNETADP;
+typedef VBOXNETADP *PVBOXNETADP;
+/* Paranoia checks for alignment and padding. */
+AssertCompileMemberAlignment(VBOXNETADP, u, ARCH_BITS/8);
+AssertCompileMemberAlignment(VBOXNETADP, szName, ARCH_BITS/8);
+AssertCompileMembersSameSize(VBOXNETADP, u, VBOXNETADP, u.abPadding);
+
+DECLHIDDEN(int) vboxNetAdpInit(void);
+DECLHIDDEN(void) vboxNetAdpShutdown(void);
+DECLHIDDEN(int) vboxNetAdpCreate(PVBOXNETADP *ppNew, const char *pcszName);
+DECLHIDDEN(int) vboxNetAdpDestroy(PVBOXNETADP pThis);
+DECLHIDDEN(PVBOXNETADP) vboxNetAdpFindByName(const char *pszName);
+DECLHIDDEN(void) vboxNetAdpComposeMACAddress(PVBOXNETADP pThis, PRTMAC pMac);
+
+
+/**
+ * This is called to perform OS-specific structure initializations.
+ *
+ * @return IPRT status code.
+ * @param pThis The new instance.
+ *
+ * @remarks Owns no locks.
+ */
+DECLHIDDEN(int) vboxNetAdpOsInit(PVBOXNETADP pThis);
+
+/**
+ * Counter part to vboxNetAdpOsCreate().
+ *
+ * @return IPRT status code.
+ * @param pThis The new instance.
+ *
+ * @remarks May own the semaphores for the global list, the network lock and the out-bound trunk port.
+ */
+DECLHIDDEN(void) vboxNetAdpOsDestroy(PVBOXNETADP pThis);
+
+/**
+ * This is called to attach to the actual host interface
+ * after linking the instance into the list.
+ *
+ * @return IPRT status code.
+ * @param pThis The new instance.
+ * @param pMac The MAC address to use for this instance.
+ *
+ * @remarks Owns no locks.
+ */
+DECLHIDDEN(int) vboxNetAdpOsCreate(PVBOXNETADP pThis, PCRTMAC pMac);
+
+
+
+RT_C_DECLS_END
+
+#endif /* !VBOX_INCLUDED_SRC_VBoxNetAdp_VBoxNetAdpInternal_h */
+
diff --git a/src/VBox/HostDrivers/VBoxNetAdp/darwin/Info.plist b/src/VBox/HostDrivers/VBoxNetAdp/darwin/Info.plist
new file mode 100644
index 00000000..c0b20e7b
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetAdp/darwin/Info.plist
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+<dict>
+ <key>CFBundleDevelopmentRegion</key> <string>English</string>
+ <key>CFBundleExecutable</key> <string>VBoxNetAdp</string>
+ <key>CFBundleIdentifier</key> <string>org.virtualbox.kext.VBoxNetAdp</string>
+ <key>CFBundleInfoDictionaryVersion</key> <string>6.0</string>
+ <key>CFBundleName</key> <string>VBoxNetAdp</string>
+ <key>CFBundlePackageType</key> <string>KEXT</string>
+ <key>CFBundleSignature</key> <string>????</string>
+ <key>CFBundleGetInfoString</key> <string>@VBOX_PRODUCT@ @VBOX_VERSION_STRING@, © 2008-@VBOX_C_YEAR@ @VBOX_VENDOR@</string>
+ <key>CFBundleVersion</key> <string>@VBOX_VERSION_MAJOR@.@VBOX_VERSION_MINOR@.@VBOX_VERSION_BUILD@</string>
+ <key>CFBundleShortVersionString</key> <string>@VBOX_VERSION_MAJOR@.@VBOX_VERSION_MINOR@.@VBOX_VERSION_BUILD@</string>
+ <key>IOKitPersonalities</key>
+ <dict>
+ </dict>
+ <key>OSBundleLibraries</key>
+ <dict>
+ <key>com.apple.kpi.bsd</key> <string>8.8.1</string>
+ <key>com.apple.kpi.mach</key> <string>8.8.1</string>
+ <key>com.apple.kpi.libkern</key> <string>8.8.1</string>
+ <key>org.virtualbox.kext.VBoxDrv</key> <string>@VBOX_VERSION_MAJOR@.@VBOX_VERSION_MINOR@.@VBOX_VERSION_BUILD@</string>
+ </dict>
+</dict>
+</plist>
diff --git a/src/VBox/HostDrivers/VBoxNetAdp/darwin/Makefile.kup b/src/VBox/HostDrivers/VBoxNetAdp/darwin/Makefile.kup
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetAdp/darwin/Makefile.kup
diff --git a/src/VBox/HostDrivers/VBoxNetAdp/darwin/VBoxNetAdp-darwin.cpp b/src/VBox/HostDrivers/VBoxNetAdp/darwin/VBoxNetAdp-darwin.cpp
new file mode 100644
index 00000000..8cfc2bb2
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetAdp/darwin/VBoxNetAdp-darwin.cpp
@@ -0,0 +1,529 @@
+/* $Id: VBoxNetAdp-darwin.cpp $ */
+/** @file
+ * VBoxNetAdp - Virtual Network Adapter Driver (Host), Darwin Specific Code.
+ */
+
+/*
+ * Copyright (C) 2008-2022 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_NET_ADP_DRV
+#include "../../../Runtime/r0drv/darwin/the-darwin-kernel.h"
+
+#include <VBox/log.h>
+#include <VBox/err.h>
+#include <VBox/version.h>
+#include <iprt/assert.h>
+#include <iprt/initterm.h>
+#include <iprt/semaphore.h>
+#include <iprt/spinlock.h>
+#include <iprt/string.h>
+#include <iprt/uuid.h>
+#include <iprt/alloca.h>
+
+#include "../../darwin/VBoxNetSend.h"
+
+#include <sys/systm.h>
+RT_C_DECLS_BEGIN /* Buggy 10.4 headers, fixed in 10.5. */
+#include <sys/kpi_mbuf.h>
+RT_C_DECLS_END
+
+#include <net/ethernet.h>
+#include <net/if_ether.h>
+#include <net/if_types.h>
+#include <sys/socket.h>
+#include <net/if.h>
+#include <net/if_dl.h>
+#include <sys/errno.h>
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <miscfs/devfs/devfs.h>
+RT_C_DECLS_BEGIN
+#include <net/bpf.h>
+RT_C_DECLS_END
+
+#define VBOXNETADP_OS_SPECFIC 1
+#include "../VBoxNetAdpInternal.h"
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+/** The maximum number of SG segments.
+ * Used to prevent stack overflow and similar bad stuff. */
+#define VBOXNETADP_DARWIN_MAX_SEGS 32
+#define VBOXNETADP_DARWIN_MAX_FAMILIES 4
+#define VBOXNETADP_DARWIN_NAME "vboxnet"
+#define VBOXNETADP_DARWIN_MTU 1500
+#define VBOXNETADP_DARWIN_DETACH_TIMEOUT 500
+
+#define VBOXNETADP_FROM_IFACE(iface) ((PVBOXNETADP) ifnet_softc(iface))
+
+
+/*********************************************************************************************************************************
+* Internal Functions *
+*********************************************************************************************************************************/
+RT_C_DECLS_BEGIN
+static kern_return_t VBoxNetAdpDarwinStart(struct kmod_info *pKModInfo, void *pvData);
+static kern_return_t VBoxNetAdpDarwinStop(struct kmod_info *pKModInfo, void *pvData);
+RT_C_DECLS_END
+
+static int VBoxNetAdpDarwinOpen(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess);
+static int VBoxNetAdpDarwinClose(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess);
+static int VBoxNetAdpDarwinIOCtl(dev_t Dev, u_long iCmd, caddr_t pData, int fFlags, struct proc *pProcess);
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+/**
+ * Declare the module stuff.
+ */
+RT_C_DECLS_BEGIN
+extern kern_return_t _start(struct kmod_info *pKModInfo, void *pvData);
+extern kern_return_t _stop(struct kmod_info *pKModInfo, void *pvData);
+
+KMOD_EXPLICIT_DECL(VBoxNetAdp, VBOX_VERSION_STRING, _start, _stop)
+DECL_HIDDEN_DATA(kmod_start_func_t *) _realmain = VBoxNetAdpDarwinStart;
+DECL_HIDDEN_DATA(kmod_stop_func_t *) _antimain = VBoxNetAdpDarwinStop;
+DECL_HIDDEN_DATA(int) _kext_apple_cc = __APPLE_CC__;
+RT_C_DECLS_END
+
+/**
+ * The (common) global data.
+ */
+static int g_nCtlDev = -1; /* Major dev number */
+static void *g_hCtlDev = 0; /* FS dev handle */
+
+/**
+ * The character device switch table for the driver.
+ */
+static struct cdevsw g_ChDev =
+{
+ /*.d_open = */VBoxNetAdpDarwinOpen,
+ /*.d_close = */VBoxNetAdpDarwinClose,
+ /*.d_read = */eno_rdwrt,
+ /*.d_write = */eno_rdwrt,
+ /*.d_ioctl = */VBoxNetAdpDarwinIOCtl,
+ /*.d_stop = */eno_stop,
+ /*.d_reset = */eno_reset,
+ /*.d_ttys = */NULL,
+ /*.d_select = */eno_select,
+ /*.d_mmap = */eno_mmap,
+ /*.d_strategy = */eno_strat,
+ /*.d_getc = */(void *)(uintptr_t)&enodev, //eno_getc,
+ /*.d_putc = */(void *)(uintptr_t)&enodev, //eno_putc,
+ /*.d_type = */0
+};
+
+
+
+static void vboxNetAdpDarwinComposeUUID(PVBOXNETADP pThis, PRTUUID pUuid)
+{
+ /* Generate UUID from name and MAC address. */
+ RTUuidClear(pUuid);
+ memcpy(pUuid->au8, "vboxnet", 7);
+ pUuid->Gen.u8ClockSeqHiAndReserved = (pUuid->Gen.u8ClockSeqHiAndReserved & 0x3f) | 0x80;
+ pUuid->Gen.u16TimeHiAndVersion = (pUuid->Gen.u16TimeHiAndVersion & 0x0fff) | 0x4000;
+ pUuid->Gen.u8ClockSeqLow = pThis->iUnit;
+ vboxNetAdpComposeMACAddress(pThis, (PRTMAC)pUuid->Gen.au8Node);
+}
+
+static errno_t vboxNetAdpDarwinOutput(ifnet_t pIface, mbuf_t pMBuf)
+{
+ /*
+ * We are a dummy interface with all the real work done in
+ * VBoxNetFlt bridged networking filter. If anything makes it
+ * this far, it must be a broadcast or a packet for an unknown
+ * guest that intnet didn't know where to dispatch. In that case
+ * we must still do the BPF tap and stats.
+ */
+ bpf_tap_out(pIface, DLT_EN10MB, pMBuf, NULL, 0);
+ ifnet_stat_increment_out(pIface, 1, mbuf_len(pMBuf), 0);
+
+ mbuf_freem_list(pMBuf);
+ return 0;
+}
+
+static void vboxNetAdpDarwinDetach(ifnet_t pIface)
+{
+ PVBOXNETADP pThis = VBOXNETADP_FROM_IFACE(pIface);
+ Assert(pThis);
+ Log2(("vboxNetAdpDarwinDetach: Signaling detach to vboxNetAdpUnregisterDevice.\n"));
+ /* Let vboxNetAdpDarwinUnregisterDevice know that the interface has been detached. */
+ RTSemEventSignal(pThis->u.s.hEvtDetached);
+}
+
+static errno_t vboxNetAdpDarwinDemux(ifnet_t pIface, mbuf_t pMBuf,
+ char *pFrameHeader,
+ protocol_family_t *pProtocolFamily)
+{
+ /*
+ * Anything we get here comes from VBoxNetFlt bridged networking
+ * filter where it has already been accounted for and fed to bpf.
+ */
+ return ether_demux(pIface, pMBuf, pFrameHeader, pProtocolFamily);
+}
+
+
+static errno_t vboxNetAdpDarwinIfIOCtl(ifnet_t pIface, unsigned long uCmd, void *pvData)
+{
+ errno_t error = 0;
+
+ if (pvData == NULL)
+ {
+ /*
+ * Common pattern in the kernel code is to make changes in the
+ * net layer and then notify the device driver by calling its
+ * ioctl function with NULL parameter, e.g.:
+ *
+ * ifnet_set_flags(interface, ...);
+ * ifnet_ioctl(interface, 0, SIOCSIFFLAGS, NULL);
+ *
+ * These are no-ops for us, so tell the caller we succeeded
+ * because some callers do check that return value.
+ */
+ switch (uCmd)
+ {
+ case SIOCSIFFLAGS:
+ Log2(("VBoxNetAdp: %s%d: SIOCSIFFLAGS (null): flags = 0x%04hx\n",
+ ifnet_name(pIface), ifnet_unit(pIface),
+ (uint16_t)ifnet_flags(pIface)));
+ return 0;
+
+ case SIOCADDMULTI:
+ case SIOCDELMULTI:
+ Log2(("VBoxNetAdp: %s%d: SIOC%sMULTI (null)\n",
+ ifnet_name(pIface), ifnet_unit(pIface),
+ uCmd == SIOCADDMULTI ? "ADD" : "DEL"));
+ return 0;
+ }
+ }
+
+ Log2(("VBoxNetAdp: %s%d: %c%c '%c' %u len %u\n",
+ ifnet_name(pIface), ifnet_unit(pIface),
+ uCmd & IOC_OUT ? '<' : '-',
+ uCmd & IOC_IN ? '>' : '-',
+ IOCGROUP(uCmd),
+ uCmd & 0xff,
+ IOCPARM_LEN(uCmd)));
+
+ error = ether_ioctl(pIface, uCmd, pvData);
+ return error;
+}
+
+
+int vboxNetAdpOsCreate(PVBOXNETADP pThis, PCRTMAC pMACAddress)
+{
+ int rc;
+ struct ifnet_init_params Params;
+ RTUUID uuid;
+ struct sockaddr_dl mac;
+
+ pThis->u.s.hEvtDetached = NIL_RTSEMEVENT;
+ rc = RTSemEventCreate(&pThis->u.s.hEvtDetached);
+ if (RT_FAILURE(rc))
+ {
+ printf("vboxNetAdpOsCreate: failed to create semaphore (rc=%d).\n", rc);
+ return rc;
+ }
+
+ mac.sdl_len = sizeof(mac);
+ mac.sdl_family = AF_LINK;
+ mac.sdl_alen = ETHER_ADDR_LEN;
+ mac.sdl_nlen = 0;
+ mac.sdl_slen = 0;
+ memcpy(LLADDR(&mac), pMACAddress->au8, mac.sdl_alen);
+
+ RTStrPrintf(pThis->szName, VBOXNETADP_MAX_NAME_LEN, "%s%d", VBOXNETADP_NAME, pThis->iUnit);
+ vboxNetAdpDarwinComposeUUID(pThis, &uuid);
+ Params.uniqueid = uuid.au8;
+ Params.uniqueid_len = sizeof(uuid);
+ Params.name = VBOXNETADP_NAME;
+ Params.unit = pThis->iUnit;
+ Params.family = IFNET_FAMILY_ETHERNET;
+ Params.type = IFT_ETHER;
+ Params.output = vboxNetAdpDarwinOutput;
+ Params.demux = vboxNetAdpDarwinDemux;
+ Params.add_proto = ether_add_proto;
+ Params.del_proto = ether_del_proto;
+ Params.check_multi = ether_check_multi;
+ Params.framer = ether_frameout;
+ Params.softc = pThis;
+ Params.ioctl = vboxNetAdpDarwinIfIOCtl;
+ Params.set_bpf_tap = NULL;
+ Params.detach = vboxNetAdpDarwinDetach;
+ Params.event = NULL;
+ Params.broadcast_addr = "\xFF\xFF\xFF\xFF\xFF\xFF";
+ Params.broadcast_len = ETHER_ADDR_LEN;
+
+ errno_t err = ifnet_allocate(&Params, &pThis->u.s.pIface);
+ if (!err)
+ {
+ err = ifnet_attach(pThis->u.s.pIface, &mac);
+ if (!err)
+ {
+ bpfattach(pThis->u.s.pIface, DLT_EN10MB, ETHER_HDR_LEN);
+
+ err = ifnet_set_flags(pThis->u.s.pIface, IFF_RUNNING | IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST, 0xFFFF);
+ if (!err)
+ {
+ ifnet_set_mtu(pThis->u.s.pIface, VBOXNETADP_MTU);
+ VBoxNetSendDummy(pThis->u.s.pIface);
+ return VINF_SUCCESS;
+ }
+ else
+ Log(("vboxNetAdpDarwinRegisterDevice: Failed to set flags (err=%d).\n", err));
+ ifnet_detach(pThis->u.s.pIface);
+ }
+ else
+ Log(("vboxNetAdpDarwinRegisterDevice: Failed to attach to interface (err=%d).\n", err));
+ ifnet_release(pThis->u.s.pIface);
+ }
+ else
+ Log(("vboxNetAdpDarwinRegisterDevice: Failed to allocate interface (err=%d).\n", err));
+
+ RTSemEventDestroy(pThis->u.s.hEvtDetached);
+ pThis->u.s.hEvtDetached = NIL_RTSEMEVENT;
+
+ return RTErrConvertFromErrno(err);
+}
+
+void vboxNetAdpOsDestroy(PVBOXNETADP pThis)
+{
+ /* Bring down the interface */
+ int rc = VINF_SUCCESS;
+ errno_t err;
+
+ AssertPtr(pThis->u.s.pIface);
+ Assert(pThis->u.s.hEvtDetached != NIL_RTSEMEVENT);
+
+ err = ifnet_set_flags(pThis->u.s.pIface, 0, IFF_UP | IFF_RUNNING);
+ if (err)
+ Log(("vboxNetAdpDarwinUnregisterDevice: Failed to bring down interface "
+ "(err=%d).\n", err));
+ err = ifnet_detach(pThis->u.s.pIface);
+ if (err)
+ Log(("vboxNetAdpDarwinUnregisterDevice: Failed to detach interface "
+ "(err=%d).\n", err));
+ Log2(("vboxNetAdpDarwinUnregisterDevice: Waiting for 'detached' event...\n"));
+ /* Wait until we get a signal from detach callback. */
+ rc = RTSemEventWait(pThis->u.s.hEvtDetached, VBOXNETADP_DETACH_TIMEOUT);
+ if (rc == VERR_TIMEOUT)
+ LogRel(("VBoxAdpDrv: Failed to detach interface %s%d\n.",
+ VBOXNETADP_NAME, pThis->iUnit));
+ err = ifnet_release(pThis->u.s.pIface);
+ if (err)
+ Log(("vboxNetAdpUnregisterDevice: Failed to release interface (err=%d).\n", err));
+
+ RTSemEventDestroy(pThis->u.s.hEvtDetached);
+ pThis->u.s.hEvtDetached = NIL_RTSEMEVENT;
+}
+
+/**
+ * Device open. Called on open /dev/vboxnetctl
+ *
+ * @param Dev The device number.
+ * @param fFlags ???.
+ * @param fDevType ???.
+ * @param pProcess The process issuing this request.
+ */
+static int VBoxNetAdpDarwinOpen(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess)
+{
+ RT_NOREF(Dev, fFlags, fDevType, pProcess);
+#ifdef LOG_ENABLED
+ char szName[128];
+ szName[0] = '\0';
+ proc_name(proc_pid(pProcess), szName, sizeof(szName));
+ Log(("VBoxNetAdpDarwinOpen: pid=%d '%s'\n", proc_pid(pProcess), szName));
+#endif
+ return 0;
+}
+
+/**
+ * Close device.
+ */
+static int VBoxNetAdpDarwinClose(dev_t Dev, int fFlags, int fDevType, struct proc *pProcess)
+{
+ RT_NOREF(Dev, fFlags, fDevType, pProcess);
+ Log(("VBoxNetAdpDarwinClose: pid=%d\n", proc_pid(pProcess)));
+ return 0;
+}
+
+/**
+ * Device I/O Control entry point.
+ *
+ * @returns Darwin for slow IOCtls and VBox status code for the fast ones.
+ * @param Dev The device number (major+minor).
+ * @param iCmd The IOCtl command.
+ * @param pData Pointer to the data (if any it's a SUPDRVIOCTLDATA (kernel copy)).
+ * @param fFlags Flag saying we're a character device (like we didn't know already).
+ * @param pProcess The process issuing this request.
+ */
+static int VBoxNetAdpDarwinIOCtl(dev_t Dev, u_long iCmd, caddr_t pData, int fFlags, struct proc *pProcess)
+{
+ RT_NOREF(Dev, fFlags, pProcess);
+ uint32_t cbReq = IOCPARM_LEN(iCmd);
+ PVBOXNETADPREQ pReq = (PVBOXNETADPREQ)pData;
+ int rc;
+
+ Log(("VBoxNetAdpDarwinIOCtl: param len %#x; iCmd=%#lx\n", cbReq, iCmd));
+ switch (IOCBASECMD(iCmd))
+ {
+ case IOCBASECMD(VBOXNETADP_CTL_ADD):
+ {
+ if ( (IOC_DIRMASK & iCmd) != IOC_INOUT
+ || cbReq < sizeof(VBOXNETADPREQ))
+ return EINVAL;
+
+ PVBOXNETADP pNew;
+ Log(("VBoxNetAdpDarwinIOCtl: szName=%s\n", pReq->szName));
+ rc = vboxNetAdpCreate(&pNew,
+ pReq->szName[0] && RTStrEnd(pReq->szName, RT_MIN(cbReq, sizeof(pReq->szName))) ?
+ pReq->szName : NULL);
+ if (RT_FAILURE(rc))
+ return rc == VERR_OUT_OF_RESOURCES ? ENOMEM : EINVAL;
+
+ Assert(strlen(pReq->szName) < sizeof(pReq->szName));
+ strncpy(pReq->szName, pNew->szName, sizeof(pReq->szName) - 1);
+ pReq->szName[sizeof(pReq->szName) - 1] = '\0';
+ Log(("VBoxNetAdpDarwinIOCtl: Added '%s'\n", pReq->szName));
+ break;
+ }
+
+ case IOCBASECMD(VBOXNETADP_CTL_REMOVE):
+ {
+ if (!RTStrEnd(pReq->szName, RT_MIN(cbReq, sizeof(pReq->szName))))
+ return EINVAL;
+
+ PVBOXNETADP pAdp = vboxNetAdpFindByName(pReq->szName);
+ if (!pAdp)
+ return EINVAL;
+
+ rc = vboxNetAdpDestroy(pAdp);
+ if (RT_FAILURE(rc))
+ return EINVAL;
+ Log(("VBoxNetAdpDarwinIOCtl: Removed %s\n", pReq->szName));
+ break;
+ }
+
+ default:
+ printf("VBoxNetAdpDarwinIOCtl: unknown command %lx.\n", IOCBASECMD(iCmd));
+ return EINVAL;
+ }
+
+ return 0;
+}
+
+int vboxNetAdpOsInit(PVBOXNETADP pThis)
+{
+ /*
+ * Init the darwin specific members.
+ */
+ pThis->u.s.pIface = NULL;
+ pThis->u.s.hEvtDetached = NIL_RTSEMEVENT;
+
+ return VINF_SUCCESS;
+}
+
+/**
+ * Start the kernel module.
+ */
+static kern_return_t VBoxNetAdpDarwinStart(struct kmod_info *pKModInfo, void *pvData)
+{
+ RT_NOREF(pKModInfo, pvData);
+ int rc;
+
+ /*
+ * Initialize IPRT and find our module tag id.
+ * (IPRT is shared with VBoxDrv, it creates the loggers.)
+ */
+ rc = RTR0Init(0);
+ if (RT_SUCCESS(rc))
+ {
+ Log(("VBoxNetAdpDarwinStart\n"));
+ rc = vboxNetAdpInit();
+ if (RT_SUCCESS(rc))
+ {
+ g_nCtlDev = cdevsw_add(-1, &g_ChDev);
+ if (g_nCtlDev < 0)
+ {
+ LogRel(("VBoxAdp: failed to register control device."));
+ rc = VERR_CANT_CREATE;
+ }
+ else
+ {
+ g_hCtlDev = devfs_make_node(makedev(g_nCtlDev, 0), DEVFS_CHAR,
+ UID_ROOT, GID_WHEEL, 0600, VBOXNETADP_CTL_DEV_NAME);
+ if (!g_hCtlDev)
+ {
+ LogRel(("VBoxAdp: failed to create FS node for control device."));
+ rc = VERR_CANT_CREATE;
+ }
+ }
+ }
+
+ if (RT_SUCCESS(rc))
+ {
+ LogRel(("VBoxAdpDrv: version " VBOX_VERSION_STRING " r%d\n", VBOX_SVN_REV));
+ return KMOD_RETURN_SUCCESS;
+ }
+
+ LogRel(("VBoxAdpDrv: failed to initialize device extension (rc=%d)\n", rc));
+ RTR0Term();
+ }
+ else
+ printf("VBoxAdpDrv: failed to initialize IPRT (rc=%d)\n", rc);
+
+ return KMOD_RETURN_FAILURE;
+}
+
+
+/**
+ * Stop the kernel module.
+ */
+static kern_return_t VBoxNetAdpDarwinStop(struct kmod_info *pKModInfo, void *pvData)
+{
+ RT_NOREF(pKModInfo, pvData);
+ Log(("VBoxNetAdpDarwinStop\n"));
+
+ vboxNetAdpShutdown();
+ /* Remove control device */
+ devfs_remove(g_hCtlDev);
+ cdevsw_remove(g_nCtlDev, &g_ChDev);
+
+ RTR0Term();
+
+ return KMOD_RETURN_SUCCESS;
+}
diff --git a/src/VBox/HostDrivers/VBoxNetAdp/darwin/loadnetadp.sh b/src/VBox/HostDrivers/VBoxNetAdp/darwin/loadnetadp.sh
new file mode 100755
index 00000000..b1bc2b12
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetAdp/darwin/loadnetadp.sh
@@ -0,0 +1,133 @@
+#!/bin/bash
+## @file
+# For development.
+#
+
+#
+# Copyright (C) 2006-2022 Oracle and/or its affiliates.
+#
+# This file is part of VirtualBox base platform packages, as
+# available from https://www.virtualbox.org.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation, in version 3 of the
+# License.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses>.
+#
+# The contents of this file may alternatively be used under the terms
+# of the Common Development and Distribution License Version 1.0
+# (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+# in the VirtualBox distribution, in which case the provisions of the
+# CDDL are applicable instead of those of the GPL.
+#
+# You may elect to license modified versions of this file under the
+# terms and conditions of either the GPL or the CDDL or both.
+#
+# SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+#
+
+SCRIPT_NAME="loadnetadp"
+XNU_VERSION=`LC_ALL=C uname -r | LC_ALL=C cut -d . -f 1`
+
+DRVNAME="VBoxNetAdp.kext"
+BUNDLE="org.virtualbox.kext.VBoxNetAdp"
+
+DEP_DRVNAME="VBoxDrv.kext"
+DEP_BUNDLE="org.virtualbox.kext.VBoxDrv"
+
+
+DIR=`dirname "$0"`
+DIR=`cd "$DIR" && pwd`
+DEP_DIR="$DIR/$DEP_DRVNAME"
+DIR="$DIR/$DRVNAME"
+if [ ! -d "$DIR" ]; then
+ echo "Cannot find $DIR or it's not a directory..."
+ exit 1;
+fi
+if [ ! -d "$DEP_DIR" ]; then
+ echo "Cannot find $DEP_DIR or it's not a directory... (dependency)"
+ exit 1;
+fi
+if [ -n "$*" ]; then
+ OPTS="$*"
+else
+ OPTS="-t"
+fi
+
+trap "sudo chown -R `whoami` $DIR $DEP_DIR; exit 1" INT
+
+# Try unload any existing instance first.
+LOADED=`kextstat -b $BUNDLE -l`
+if test -n "$LOADED"; then
+ echo "${SCRIPT_NAME}.sh: Unloading $BUNDLE..."
+ sudo kextunload -v 6 -b $BUNDLE
+ LOADED=`kextstat -b $BUNDLE -l`
+ if test -n "$LOADED"; then
+ echo "${SCRIPT_NAME}.sh: failed to unload $BUNDLE, see above..."
+ exit 1;
+ fi
+ echo "${SCRIPT_NAME}.sh: Successfully unloaded $BUNDLE"
+fi
+
+set -e
+
+# Copy the .kext to the symbols directory and tweak the kextload options.
+if test -n "$VBOX_DARWIN_SYMS"; then
+ echo "${SCRIPT_NAME}.sh: copying the extension the symbol area..."
+ rm -Rf "$VBOX_DARWIN_SYMS/$DRVNAME"
+ mkdir -p "$VBOX_DARWIN_SYMS"
+ cp -R "$DIR" "$VBOX_DARWIN_SYMS/"
+ OPTS="$OPTS -s $VBOX_DARWIN_SYMS/ "
+ sync
+fi
+
+# On smbfs, this might succeed just fine but make no actual changes,
+# so we might have to temporarily copy the driver to a local directory.
+if sudo chown -R root:wheel "$DIR" "$DEP_DIR"; then
+ OWNER=`/usr/bin/stat -f "%u" "$DIR"`
+else
+ OWNER=1000
+fi
+if test "$OWNER" -ne 0; then
+ TMP_DIR=/tmp/${SCRIPT_NAME}.tmp
+ echo "${SCRIPT_NAME}.sh: chown didn't work on $DIR, using temp location $TMP_DIR/$DRVNAME"
+
+ # clean up first (no sudo rm)
+ if test -e "$TMP_DIR"; then
+ sudo chown -R `whoami` "$TMP_DIR"
+ rm -Rf "$TMP_DIR"
+ fi
+
+ # make a copy and switch over DIR
+ mkdir -p "$TMP_DIR/"
+ sudo cp -Rp "$DIR" "$TMP_DIR/"
+ DIR="$TMP_DIR/$DRVNAME"
+
+ # load.sh puts it here.
+ DEP_DIR="/tmp/loaddrv.tmp/$DEP_DRVNAME"
+
+ # retry
+ sudo chown -R root:wheel "$DIR" "$DEP_DIR"
+fi
+
+sudo chmod -R o-rwx "$DIR"
+sync
+if [ "$XNU_VERSION" -ge "10" ]; then
+ echo "${SCRIPT_NAME}.sh: loading $DIR... (kextutil $OPTS -d \"$DEP_DIR\" \"$DIR\")"
+ sudo kextutil $OPTS -d "$DEP_DIR" "$DIR"
+else
+ echo "${SCRIPT_NAME}.sh: loading $DIR... (kextload $OPTS -d \"$DEP_DIR\" \"$DIR\")"
+sudo kextload $OPTS -d "$DEP_DIR" "$DIR"
+fi
+sync
+sudo chown -R `whoami` "$DIR" "$DEP_DIR"
+kextstat | grep org.virtualbox.kext
+
diff --git a/src/VBox/HostDrivers/VBoxNetAdp/freebsd/Makefile b/src/VBox/HostDrivers/VBoxNetAdp/freebsd/Makefile
new file mode 100644
index 00000000..c3196563
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetAdp/freebsd/Makefile
@@ -0,0 +1,54 @@
+# $Id: Makefile $
+## @file
+# Makefile for the VirtualBox FreeBSD Host Driver.
+#
+
+#
+# Copyright (C) 2006-2022 Oracle and/or its affiliates.
+#
+# This file is part of VirtualBox base platform packages, as
+# available from https://www.virtualbox.org.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation, in version 3 of the
+# License.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses>.
+#
+# The contents of this file may alternatively be used under the terms
+# of the Common Development and Distribution License Version 1.0
+# (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+# in the VirtualBox distribution, in which case the provisions of the
+# CDDL are applicable instead of those of the GPL.
+#
+# You may elect to license modified versions of this file under the
+# terms and conditions of either the GPL or the CDDL or both.
+#
+# SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+#
+
+KMOD = vboxnetadp
+
+CFLAGS += -DRT_OS_FREEBSD -DIN_RING0 -DIN_RT_R0 -DIN_SUP_R0 -DVBOX -DRT_WITH_VBOX -Iinclude -I. -Ir0drv -w -DVBOX_WITH_HARDENING -DVIMAGE
+
+.if (${MACHINE_ARCH} == "i386")
+ CFLAGS += -DRT_ARCH_X86
+.elif (${MACHINE_ARCH} == "amd64")
+ CFLAGS += -DRT_ARCH_AMD64
+.endif
+
+SRCS = \
+ VBoxNetAdp-freebsd.c \
+ VBoxNetAdp.c
+
+SRCS += device_if.h bus_if.h
+
+.include <bsd.kmod.mk>
+
diff --git a/src/VBox/HostDrivers/VBoxNetAdp/freebsd/VBoxNetAdp-freebsd.c b/src/VBox/HostDrivers/VBoxNetAdp/freebsd/VBoxNetAdp-freebsd.c
new file mode 100644
index 00000000..db5c0b64
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetAdp/freebsd/VBoxNetAdp-freebsd.c
@@ -0,0 +1,339 @@
+/* $Id: VBoxNetAdp-freebsd.c $ */
+/** @file
+ * VBoxNetAdp - Virtual Network Adapter Driver (Host), FreeBSD Specific Code.
+ */
+
+/*-
+ * Copyright (c) 2009 Fredrik Lindberg <fli@shapeshifter.se>
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include <sys/param.h>
+#undef PVM
+#include <sys/types.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/errno.h>
+#include <sys/kernel.h>
+#include <sys/fcntl.h>
+#include <sys/conf.h>
+#include <sys/uio.h>
+#include <sys/socket.h>
+#include <sys/sockio.h>
+
+#include <net/if.h>
+#include <net/if_var.h>
+#include <net/route.h>
+#include <net/if_dl.h>
+#include <net/if_media.h>
+#include <net/if_types.h>
+#include <net/ethernet.h>
+#include <net/bpf.h>
+
+#define LOG_GROUP LOG_GROUP_NET_ADP_DRV
+#include <VBox/version.h>
+#include <iprt/errcore.h>
+#include <VBox/log.h>
+#include <iprt/initterm.h>
+#include <iprt/string.h>
+#include <iprt/spinlock.h>
+#include <iprt/process.h>
+#include <iprt/assert.h>
+#include <iprt/uuid.h>
+#include <iprt/alloc.h>
+#include <iprt/errcore.h>
+
+#define VBOXNETADP_OS_SPECFIC 1
+#include "../VBoxNetAdpInternal.h"
+
+#if defined(__FreeBSD_version) && __FreeBSD_version >= 800500
+# include <sys/jail.h>
+# include <net/vnet.h>
+
+# define VBOXCURVNET_SET(arg) CURVNET_SET_QUIET(arg)
+# define VBOXCURVNET_SET_FROM_UCRED() VBOXCURVNET_SET(CRED_TO_VNET(curthread->td_ucred))
+# define VBOXCURVNET_RESTORE() CURVNET_RESTORE()
+
+#else /* !defined(__FreeBSD_version) || __FreeBSD_version < 800500 */
+
+# define VBOXCURVNET_SET(arg)
+# define VBOXCURVNET_SET_FROM_UCRED()
+# define VBOXCURVNET_RESTORE()
+
+#endif /* !defined(__FreeBSD_version) || __FreeBSD_version < 800500 */
+
+static int VBoxNetAdpFreeBSDCtrlioctl(struct cdev *, u_long, caddr_t, int flags,
+ struct thread *);
+static struct cdevsw vboxnetadp_cdevsw =
+{
+ .d_version = D_VERSION,
+ .d_ioctl = VBoxNetAdpFreeBSDCtrlioctl,
+ .d_read = (d_read_t *)nullop,
+ .d_write = (d_write_t *)nullop,
+ .d_name = VBOXNETADP_CTL_DEV_NAME,
+};
+
+static struct cdev *VBoxNetAdpFreeBSDcdev;
+
+static int VBoxNetAdpFreeBSDModuleEvent(struct module *, int, void *);
+static moduledata_t g_VBoxNetAdpFreeBSDModule = {
+ "vboxnetadp",
+ VBoxNetAdpFreeBSDModuleEvent,
+ NULL
+};
+
+/** Declare the module as a pseudo device. */
+DECLARE_MODULE(vboxnetadp, g_VBoxNetAdpFreeBSDModule, SI_SUB_PSEUDO, SI_ORDER_ANY);
+MODULE_VERSION(vboxnetadp, 1);
+MODULE_DEPEND(vboxnetadp, vboxdrv, 1, 1, 1);
+MODULE_DEPEND(vboxnetadp, vboxnetflt, 1, 1, 1);
+
+/**
+ * Module event handler
+ */
+static int
+VBoxNetAdpFreeBSDModuleEvent(struct module *pMod, int enmEventType, void *pvArg)
+{
+ int rc = 0;
+
+ Log(("VBoxNetAdpFreeBSDModuleEvent\n"));
+
+ switch (enmEventType)
+ {
+ case MOD_LOAD:
+ rc = RTR0Init(0);
+ if (RT_FAILURE(rc))
+ {
+ Log(("RTR0Init failed %d\n", rc));
+ return RTErrConvertToErrno(rc);
+ }
+ rc = vboxNetAdpInit();
+ if (RT_FAILURE(rc))
+ {
+ RTR0Term();
+ Log(("vboxNetAdpInit failed %d\n", rc));
+ return RTErrConvertToErrno(rc);
+ }
+ /* Create dev node */
+ VBoxNetAdpFreeBSDcdev = make_dev(&vboxnetadp_cdevsw, 0,
+ UID_ROOT, GID_WHEEL, 0600, VBOXNETADP_CTL_DEV_NAME);
+
+ break;
+
+ case MOD_UNLOAD:
+ vboxNetAdpShutdown();
+ destroy_dev(VBoxNetAdpFreeBSDcdev);
+ RTR0Term();
+ break;
+ case MOD_SHUTDOWN:
+ case MOD_QUIESCE:
+ default:
+ return EOPNOTSUPP;
+ }
+
+ if (RT_SUCCESS(rc))
+ return 0;
+ return RTErrConvertToErrno(rc);
+}
+
+/**
+ * Device I/O Control entry point.
+ */
+static int
+VBoxNetAdpFreeBSDCtrlioctl(struct cdev *dev, u_long iCmd, caddr_t data, int flags, struct thread *td)
+{
+ PVBOXNETADP pAdp;
+ PVBOXNETADPREQ pReq = (PVBOXNETADPREQ)data;
+ struct ifnet *ifp;
+ int rc;
+
+ switch (iCmd)
+ {
+ case VBOXNETADP_CTL_ADD:
+ if ( !(iCmd & IOC_INOUT) /* paranoia*/
+ || IOCPARM_LEN(iCmd) < sizeof(*pReq))
+ return EINVAL;
+
+ rc = vboxNetAdpCreate(&pAdp,
+ pReq->szName[0] && RTStrEnd(pReq->szName, RT_MIN(IOCPARM_LEN(iCmd), sizeof(pReq->szName))) ?
+ pReq->szName : NULL);
+ if (RT_FAILURE(rc))
+ return EINVAL;
+
+ strncpy(pReq->szName, pAdp->szName, sizeof(pReq->szName) - 1);
+ pReq->szName[sizeof(pReq->szName) - 1] = '\0';
+ break;
+
+ case VBOXNETADP_CTL_REMOVE:
+ if (!RTStrEnd(pReq->szName, RT_MIN(sizeof(pReq->szName), IOCPARM_LEN(iCmd))))
+ return EINVAL;
+
+ pAdp = vboxNetAdpFindByName(pReq->szName);
+ if (!pAdp)
+ return EINVAL;
+
+ rc = vboxNetAdpDestroy(pAdp);
+ if (RT_FAILURE(rc))
+ return EINVAL;
+
+ break;
+
+ default:
+ return EINVAL;
+ }
+ return 0;
+}
+
+/**
+ * Initialize device, just set the running flag.
+ */
+static void VBoxNetAdpFreeBSDNetinit(void *priv)
+{
+ PVBOXNETADP pThis = priv;
+ struct ifnet *ifp = pThis->u.s.ifp;
+
+ ifp->if_drv_flags |= IFF_DRV_RUNNING;
+}
+
+/**
+ * Transmit packets.
+ * netflt has already done everything for us so we just hand the
+ * packets to BPF and increment the packet stats.
+ */
+static void VBoxNetAdpFreeBSDNetstart(struct ifnet *ifp)
+{
+ PVBOXNETADP pThis = ifp->if_softc;
+ struct mbuf *m;
+
+ if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) != IFF_DRV_RUNNING)
+ return;
+
+ ifp->if_drv_flags |= IFF_DRV_OACTIVE;
+ while (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
+ {
+#if __FreeBSD_version >= 1100036
+ if_inc_counter(ifp, IFCOUNTER_OPACKETS, 1);
+#else
+ ifp->if_opackets++;
+#endif
+ IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
+ BPF_MTAP(ifp, m);
+ m_freem(m);
+ }
+ ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
+}
+
+/**
+ * Interface ioctl handling
+ */
+static int VBoxNetAdpFreeBSDNetioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
+{
+ int error = 0;
+
+ switch (cmd)
+ {
+ case SIOCSIFFLAGS:
+ if (ifp->if_flags & IFF_UP)
+ {
+ if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
+ ifp->if_init(ifp->if_softc);
+ }
+ else
+ {
+ if (ifp->if_drv_flags & IFF_DRV_RUNNING)
+ ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
+ }
+ break;
+ case SIOCGIFMEDIA:
+ {
+ struct ifmediareq *ifmr;
+ int count;
+
+ ifmr = (struct ifmediareq *)data;
+ count = ifmr->ifm_count;
+ ifmr->ifm_count = 1;
+ ifmr->ifm_status = IFM_AVALID;
+ ifmr->ifm_active = IFM_ETHER;
+ ifmr->ifm_status |= IFM_ACTIVE;
+ ifmr->ifm_current = ifmr->ifm_active;
+ if (count >= 1)
+ {
+ int media = IFM_ETHER;
+ error = copyout(&media, ifmr->ifm_ulist, sizeof(int));
+ }
+ break;
+ }
+ default:
+ return ether_ioctl(ifp, cmd, data);
+ }
+ return error;
+}
+
+int vboxNetAdpOsInit(PVBOXNETADP pThis)
+{
+ pThis->u.s.ifp = NULL;
+ return VINF_SUCCESS;;
+}
+
+int vboxNetAdpOsCreate(PVBOXNETADP pThis, PCRTMAC pMac)
+{
+ struct ifnet *ifp;
+
+ VBOXCURVNET_SET_FROM_UCRED();
+ ifp = if_alloc(IFT_ETHER);
+ if (ifp == NULL)
+ return VERR_NO_MEMORY;
+
+ if_initname(ifp, VBOXNETADP_NAME, pThis->iUnit);
+ ifp->if_softc = pThis;
+ ifp->if_mtu = ETHERMTU;
+ ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
+ ifp->if_ioctl = VBoxNetAdpFreeBSDNetioctl;
+ ifp->if_start = VBoxNetAdpFreeBSDNetstart;
+ ifp->if_init = VBoxNetAdpFreeBSDNetinit;
+ IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
+ ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
+ IFQ_SET_READY(&ifp->if_snd);
+ ether_ifattach(ifp, (void *)pMac);
+ ifp->if_baudrate = 0;
+
+ strncpy(pThis->szName, ifp->if_xname, VBOXNETADP_MAX_NAME_LEN);
+ pThis->u.s.ifp = ifp;
+ VBOXCURVNET_RESTORE();
+ return 0;
+}
+
+void vboxNetAdpOsDestroy(PVBOXNETADP pThis)
+{
+ struct ifnet *ifp;
+
+ ifp = pThis->u.s.ifp;
+ VBOXCURVNET_SET(ifp->if_vnet);
+ ether_ifdetach(ifp);
+ if_free(ifp);
+ VBOXCURVNET_RESTORE();
+}
diff --git a/src/VBox/HostDrivers/VBoxNetAdp/freebsd/files_vboxnetadp b/src/VBox/HostDrivers/VBoxNetAdp/freebsd/files_vboxnetadp
new file mode 100755
index 00000000..5a4ecbd1
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetAdp/freebsd/files_vboxnetadp
@@ -0,0 +1,94 @@
+#!/bin/sh
+# $Id: files_vboxnetadp $
+## @file
+# Shared file between Makefile.kmk and export_modules.sh.
+#
+
+#
+# Copyright (C) 2007-2022 Oracle and/or its affiliates.
+#
+# This file is part of VirtualBox base platform packages, as
+# available from https://www.virtualbox.org.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation, in version 3 of the
+# License.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses>.
+#
+# The contents of this file may alternatively be used under the terms
+# of the Common Development and Distribution License Version 1.0
+# (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+# in the VirtualBox distribution, in which case the provisions of the
+# CDDL are applicable instead of those of the GPL.
+#
+# You may elect to license modified versions of this file under the
+# terms and conditions of either the GPL or the CDDL or both.
+#
+# SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+#
+
+
+VBOX_VBOXNETADP_SOURCES=" \
+ ${PATH_ROOT}/include/iprt/alloc.h=>include/iprt/alloc.h \
+ ${PATH_ROOT}/include/iprt/alloca.h=>include/iprt/alloca.h \
+ ${PATH_ROOT}/include/iprt/asm.h=>include/iprt/asm.h \
+ ${PATH_ROOT}/include/iprt/asm-amd64-x86.h=>include/iprt/asm-amd64-x86.h \
+ ${PATH_ROOT}/include/iprt/asm-math.h=>include/iprt/asm-math.h \
+ ${PATH_ROOT}/include/iprt/assert.h=>include/iprt/assert.h \
+ ${PATH_ROOT}/include/iprt/assertcompile.h=>include/iprt/assertcompile.h \
+ ${PATH_ROOT}/include/iprt/avl.h=>include/iprt/avl.h \
+ ${PATH_ROOT}/include/iprt/cdefs.h=>include/iprt/cdefs.h \
+ ${PATH_ROOT}/include/iprt/cpuset.h=>include/iprt/cpuset.h \
+ ${PATH_ROOT}/include/iprt/ctype.h=>include/iprt/ctype.h \
+ ${PATH_ROOT}/include/iprt/err.h=>include/iprt/err.h \
+ ${PATH_ROOT}/include/iprt/errcore.h=>include/iprt/errcore.h \
+ ${PATH_ROOT}/include/iprt/heap.h=>include/iprt/heap.h \
+ ${PATH_ROOT}/include/iprt/initterm.h=>include/iprt/initterm.h \
+ ${PATH_ROOT}/include/iprt/latin1.h=>include/iprt/latin1.h \
+ ${PATH_ROOT}/include/iprt/log.h=>include/iprt/log.h \
+ ${PATH_ROOT}/include/iprt/mangling.h=>include/iprt/mangling.h \
+ ${PATH_ROOT}/include/iprt/mem.h=>include/iprt/mem.h \
+ ${PATH_ROOT}/include/iprt/memobj.h=>include/iprt/memobj.h \
+ ${PATH_ROOT}/include/iprt/mp.h=>include/iprt/mp.h \
+ ${PATH_ROOT}/include/iprt/param.h=>include/iprt/param.h \
+ ${PATH_ROOT}/include/iprt/power.h=>include/iprt/power.h \
+ ${PATH_ROOT}/include/iprt/process.h=>include/iprt/process.h \
+ ${PATH_ROOT}/include/iprt/semaphore.h=>include/iprt/semaphore.h \
+ ${PATH_ROOT}/include/iprt/spinlock.h=>include/iprt/spinlock.h \
+ ${PATH_ROOT}/include/iprt/stdarg.h=>include/iprt/stdarg.h \
+ ${PATH_ROOT}/include/iprt/stdint.h=>include/iprt/stdint.h \
+ ${PATH_ROOT}/include/iprt/string.h=>include/iprt/string.h \
+ ${PATH_ROOT}/include/iprt/thread.h=>include/iprt/thread.h \
+ ${PATH_ROOT}/include/iprt/time.h=>include/iprt/time.h \
+ ${PATH_ROOT}/include/iprt/timer.h=>include/iprt/timer.h \
+ ${PATH_ROOT}/include/iprt/types.h=>include/iprt/types.h \
+ ${PATH_ROOT}/include/iprt/uni.h=>include/iprt/uni.h \
+ ${PATH_ROOT}/include/iprt/utf16.h=>include/iprt/utf16.h \
+ ${PATH_ROOT}/include/iprt/uuid.h=>include/iprt/uuid.h \
+ ${PATH_ROOT}/include/iprt/x86-helpers.h=>include/iprt/x86-helpers.h \
+ ${PATH_ROOT}/include/iprt/nocrt/limits.h=>include/iprt/nocrt/limits.h \
+ ${PATH_ROOT}/include/VBox/cdefs.h=>include/VBox/cdefs.h \
+ ${PATH_ROOT}/include/VBox/err.h=>include/VBox/err.h \
+ ${PATH_ROOT}/include/VBox/log.h=>include/VBox/log.h \
+ ${PATH_ROOT}/include/VBox/intnet.h=>include/VBox/intnet.h \
+ ${PATH_ROOT}/include/VBox/vmm/stam.h=>include/VBox/vmm/stam.h \
+ ${PATH_ROOT}/include/VBox/sup.h=>include/VBox/sup.h \
+ ${PATH_ROOT}/include/VBox/types.h=>include/VBox/types.h \
+ ${PATH_ROOT}/include/VBox/version.h=>include/VBox/version.h \
+ ${PATH_ROOT}/include/VBox/SUPDrvMangling.h=>include/VBox/SUPDrvMangling.h \
+ ${PATH_ROOT}/src/VBox/HostDrivers/VBoxNetAdp/freebsd/VBoxNetAdp-freebsd.c=>VBoxNetAdp-freebsd.c \
+ ${PATH_ROOT}/src/VBox/HostDrivers/VBoxNetAdp/VBoxNetAdp.c=>VBoxNetAdp.c \
+ ${PATH_ROOT}/src/VBox/HostDrivers/VBoxNetAdp/VBoxNetAdpInternal.h=>VBoxNetAdpInternal.h \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/freebsd/the-freebsd-kernel.h=>r0drv/freebsd/the-freebsd-kernel.h \
+ ${PATH_OUT}/version-generated.h=>version-generated.h \
+ ${PATH_OUT}/product-generated.h=>product-generated.h \
+"
+
diff --git a/src/VBox/HostDrivers/VBoxNetAdp/linux/Makefile b/src/VBox/HostDrivers/VBoxNetAdp/linux/Makefile
new file mode 100644
index 00000000..0f2cd01a
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetAdp/linux/Makefile
@@ -0,0 +1,78 @@
+# $Id: Makefile $
+## @file
+# Makefile for the VirtualBox Linux Host Virtual Network Adapter Driver.
+#
+
+#
+# Copyright (C) 2006-2022 Oracle and/or its affiliates.
+#
+# This file is part of VirtualBox base platform packages, as
+# available from https://www.virtualbox.org.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation, in version 3 of the
+# License.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses>.
+#
+# The contents of this file may alternatively be used under the terms
+# of the Common Development and Distribution License Version 1.0
+# (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+# in the VirtualBox distribution, in which case the provisions of the
+# CDDL are applicable instead of those of the GPL.
+#
+# You may elect to license modified versions of this file under the
+# terms and conditions of either the GPL or the CDDL or both.
+#
+# SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+#
+
+# Linux kbuild sets this to our source directory if we are called from there
+obj ?= $(CURDIR)
+include $(obj)/Makefile-header.gmk
+VBOXNETADP_DIR := $(VBOX_MODULE_SRC_DIR)
+
+# Allow building directly from the subdirectory without assuming the toplevel
+# makefile has done the copying. Not the default use case, but can be handy.
+ifndef KBUILD_EXTRA_SYMBOLS
+KBUILD_EXTRA_SYMBOLS=$(abspath $(VBOXNETADP_DIR)/../vboxdrv/Module.symvers)
+endif
+
+VBOXMOD_NAME = vboxnetadp
+VBOXMOD_OBJS = \
+ linux/VBoxNetAdp-linux.o \
+ VBoxNetAdp.o
+ifeq ($(VBOX_KBUILD_TARGET_ARCH),x86)
+VBOXMOD_OBJS += \
+ math/gcc/divdi3.o \
+ math/gcc/moddi3.o \
+ math/gcc/qdivrem.o \
+ math/gcc/udivdi3.o \
+ math/gcc/udivmoddi4.o \
+ math/gcc/divdi3.o \
+ math/gcc/umoddi3.o
+endif
+VBOXMOD_INCL = \
+ $(VBOXNETADP_DIR) \
+ $(VBOXNETADP_DIR)include \
+ $(VBOXNETADP_DIR)r0drv/linux
+VBOXMOD_DEFS = \
+ RT_OS_LINUX \
+ IN_RING0 \
+ IN_RT_R0 \
+ IN_SUP_R0 \
+ VBOX \
+ RT_WITH_VBOX \
+ VBOX_WITH_HARDENING \
+ VBOX_WITH_64_BITS_GUESTS # <-- must be consistent with Config.kmk!
+VBOXMOD_CFLAGS = -include $(VBOXNETADP_DIR)include/VBox/SUPDrvMangling.h -fno-pie -Wno-declaration-after-statement
+
+include $(obj)/Makefile-footer.gmk
+
diff --git a/src/VBox/HostDrivers/VBoxNetAdp/linux/Makefile.kup b/src/VBox/HostDrivers/VBoxNetAdp/linux/Makefile.kup
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetAdp/linux/Makefile.kup
diff --git a/src/VBox/HostDrivers/VBoxNetAdp/linux/VBoxNetAdp-linux.c b/src/VBox/HostDrivers/VBoxNetAdp/linux/VBoxNetAdp-linux.c
new file mode 100644
index 00000000..d750b941
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetAdp/linux/VBoxNetAdp-linux.c
@@ -0,0 +1,583 @@
+/* $Id: VBoxNetAdp-linux.c $ */
+/** @file
+ * VBoxNetAdp - Virtual Network Adapter Driver (Host), Linux Specific Code.
+ */
+
+/*
+ * Copyright (C) 2009-2022 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#include "the-linux-kernel.h"
+#include "version-generated.h"
+#include "revision-generated.h"
+#include "product-generated.h"
+#include <linux/ethtool.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/miscdevice.h>
+
+#define LOG_GROUP LOG_GROUP_NET_ADP_DRV
+#include <VBox/log.h>
+#include <iprt/errcore.h>
+#include <iprt/process.h>
+#include <iprt/initterm.h>
+#include <iprt/mem.h>
+#include <iprt/string.h>
+
+/*
+#include <iprt/assert.h>
+#include <iprt/semaphore.h>
+#include <iprt/spinlock.h>
+#include <iprt/string.h>
+#include <iprt/uuid.h>
+#include <iprt/alloca.h>
+*/
+
+#define VBOXNETADP_OS_SPECFIC 1
+#include "../VBoxNetAdpInternal.h"
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+#define VBOXNETADP_LINUX_NAME "vboxnet%d"
+#define VBOXNETADP_CTL_DEV_NAME "vboxnetctl"
+
+#define VBOXNETADP_FROM_IFACE(iface) ((PVBOXNETADP) ifnet_softc(iface))
+
+/** Set netdev MAC address. */
+#if RTLNX_VER_MIN(5,17,0)
+# define VBOX_DEV_ADDR_SET(dev, addr, len) dev_addr_mod(dev, 0, addr, len)
+#else /* < 5.17.0 */
+# define VBOX_DEV_ADDR_SET(dev, addr, len) memcpy(dev->dev_addr, addr, len)
+#endif
+
+
+/*********************************************************************************************************************************
+* Internal Functions *
+*********************************************************************************************************************************/
+static int __init VBoxNetAdpLinuxInit(void);
+static void __exit VBoxNetAdpLinuxUnload(void);
+
+static int VBoxNetAdpLinuxOpen(struct inode *pInode, struct file *pFilp);
+static int VBoxNetAdpLinuxClose(struct inode *pInode, struct file *pFilp);
+#if RTLNX_VER_MAX(2,6,36)
+static int VBoxNetAdpLinuxIOCtl(struct inode *pInode, struct file *pFilp,
+ unsigned int uCmd, unsigned long ulArg);
+#else /* >= 2,6,36 */
+static long VBoxNetAdpLinuxIOCtlUnlocked(struct file *pFilp,
+ unsigned int uCmd, unsigned long ulArg);
+#endif /* >= 2,6,36 */
+
+static void vboxNetAdpEthGetDrvinfo(struct net_device *dev, struct ethtool_drvinfo *info);
+#if RTLNX_VER_MIN(4,20,0)
+static int vboxNetAdpEthGetLinkSettings(struct net_device *pNetDev, struct ethtool_link_ksettings *pLinkSettings);
+#else /* < 4,20,0 */
+static int vboxNetAdpEthGetSettings(struct net_device *dev, struct ethtool_cmd *cmd);
+#endif /* < 4,20,0 */
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+module_init(VBoxNetAdpLinuxInit);
+module_exit(VBoxNetAdpLinuxUnload);
+
+MODULE_AUTHOR(VBOX_VENDOR);
+MODULE_DESCRIPTION(VBOX_PRODUCT " Network Adapter Driver");
+MODULE_LICENSE("GPL");
+#ifdef MODULE_VERSION
+MODULE_VERSION(VBOX_VERSION_STRING " r" RT_XSTR(VBOX_SVN_REV) " (" RT_XSTR(INTNETTRUNKIFPORT_VERSION) ")");
+#endif
+
+/**
+ * The (common) global data.
+ */
+static struct file_operations gFileOpsVBoxNetAdp =
+{
+ owner: THIS_MODULE,
+ open: VBoxNetAdpLinuxOpen,
+ release: VBoxNetAdpLinuxClose,
+#if RTLNX_VER_MAX(2,6,36)
+ ioctl: VBoxNetAdpLinuxIOCtl,
+#else /* RTLNX_VER_MIN(2,6,36) */
+ unlocked_ioctl: VBoxNetAdpLinuxIOCtlUnlocked,
+#endif /* RTLNX_VER_MIN(2,6,36) */
+};
+
+/** The miscdevice structure. */
+static struct miscdevice g_CtlDev =
+{
+ minor: MISC_DYNAMIC_MINOR,
+ name: VBOXNETADP_CTL_DEV_NAME,
+ fops: &gFileOpsVBoxNetAdp,
+# if RTLNX_VER_MAX(2,6,18)
+ devfs_name: VBOXNETADP_CTL_DEV_NAME
+# endif
+};
+
+# if RTLNX_VER_MIN(2,6,19)
+static const struct ethtool_ops gEthToolOpsVBoxNetAdp =
+# else
+static struct ethtool_ops gEthToolOpsVBoxNetAdp =
+# endif
+{
+ .get_drvinfo = vboxNetAdpEthGetDrvinfo,
+# if RTLNX_VER_MIN(4,20,0)
+ .get_link_ksettings = vboxNetAdpEthGetLinkSettings,
+# else
+ .get_settings = vboxNetAdpEthGetSettings,
+# endif
+ .get_link = ethtool_op_get_link,
+};
+
+
+struct VBoxNetAdpPriv
+{
+ struct net_device_stats Stats;
+};
+
+typedef struct VBoxNetAdpPriv VBOXNETADPPRIV;
+typedef VBOXNETADPPRIV *PVBOXNETADPPRIV;
+
+static int vboxNetAdpLinuxOpen(struct net_device *pNetDev)
+{
+ netif_start_queue(pNetDev);
+ return 0;
+}
+
+static int vboxNetAdpLinuxStop(struct net_device *pNetDev)
+{
+ netif_stop_queue(pNetDev);
+ return 0;
+}
+
+static int vboxNetAdpLinuxXmit(struct sk_buff *pSkb, struct net_device *pNetDev)
+{
+ PVBOXNETADPPRIV pPriv = netdev_priv(pNetDev);
+
+ /* Update the stats. */
+ pPriv->Stats.tx_packets++;
+ pPriv->Stats.tx_bytes += pSkb->len;
+#if RTLNX_VER_MAX(2,6,31)
+ /* Update transmission time stamp. */
+ pNetDev->trans_start = jiffies;
+#endif
+ /* Nothing else to do, just free the sk_buff. */
+ dev_kfree_skb(pSkb);
+ return 0;
+}
+
+static struct net_device_stats *vboxNetAdpLinuxGetStats(struct net_device *pNetDev)
+{
+ PVBOXNETADPPRIV pPriv = netdev_priv(pNetDev);
+ return &pPriv->Stats;
+}
+
+
+/* ethtool_ops::get_drvinfo */
+static void vboxNetAdpEthGetDrvinfo(struct net_device *pNetDev, struct ethtool_drvinfo *info)
+{
+ PVBOXNETADPPRIV pPriv = netdev_priv(pNetDev);
+ NOREF(pPriv);
+
+ RTStrPrintf(info->driver, sizeof(info->driver),
+ "%s", VBOXNETADP_NAME);
+
+ /*
+ * Would be nice to include VBOX_SVN_REV, but it's not available
+ * here. Use file's svn revision via svn keyword?
+ */
+ RTStrPrintf(info->version, sizeof(info->version),
+ "%s", VBOX_VERSION_STRING);
+
+ RTStrPrintf(info->fw_version, sizeof(info->fw_version),
+ "0x%08X", INTNETTRUNKIFPORT_VERSION);
+
+ RTStrPrintf(info->bus_info, sizeof(info->driver),
+ "N/A");
+}
+
+
+# if RTLNX_VER_MIN(4,20,0)
+/* ethtool_ops::get_link_ksettings */
+static int vboxNetAdpEthGetLinkSettings(struct net_device *pNetDev, struct ethtool_link_ksettings *pLinkSettings)
+{
+ /* We just need to set field we care for, the rest is done by ethtool_get_link_ksettings() helper in ethtool. */
+ ethtool_link_ksettings_zero_link_mode(pLinkSettings, supported);
+ ethtool_link_ksettings_zero_link_mode(pLinkSettings, advertising);
+ ethtool_link_ksettings_zero_link_mode(pLinkSettings, lp_advertising);
+ pLinkSettings->base.speed = SPEED_10;
+ pLinkSettings->base.duplex = DUPLEX_FULL;
+ pLinkSettings->base.port = PORT_TP;
+ pLinkSettings->base.phy_address = 0;
+ pLinkSettings->base.transceiver = XCVR_INTERNAL;
+ pLinkSettings->base.autoneg = AUTONEG_DISABLE;
+ return 0;
+}
+#else /* RTLNX_VER_MAX(4,20,0) */
+/* ethtool_ops::get_settings */
+static int vboxNetAdpEthGetSettings(struct net_device *pNetDev, struct ethtool_cmd *cmd)
+{
+ cmd->supported = 0;
+ cmd->advertising = 0;
+#if RTLNX_VER_MIN(2,6,27)
+ ethtool_cmd_speed_set(cmd, SPEED_10);
+#else
+ cmd->speed = SPEED_10;
+#endif
+ cmd->duplex = DUPLEX_FULL;
+ cmd->port = PORT_TP;
+ cmd->phy_address = 0;
+ cmd->transceiver = XCVR_INTERNAL;
+ cmd->autoneg = AUTONEG_DISABLE;
+ cmd->maxtxpkt = 0;
+ cmd->maxrxpkt = 0;
+ return 0;
+}
+#endif /* RTLNX_VER_MAX(4,20,0) */
+
+
+#if RTLNX_VER_MIN(2,6,29)
+static const struct net_device_ops vboxNetAdpNetdevOps = {
+ .ndo_open = vboxNetAdpLinuxOpen,
+ .ndo_stop = vboxNetAdpLinuxStop,
+ .ndo_start_xmit = vboxNetAdpLinuxXmit,
+ .ndo_get_stats = vboxNetAdpLinuxGetStats
+};
+#endif
+
+static void vboxNetAdpNetDevInit(struct net_device *pNetDev)
+{
+ PVBOXNETADPPRIV pPriv;
+
+ ether_setup(pNetDev);
+#if RTLNX_VER_MIN(2,6,29)
+ pNetDev->netdev_ops = &vboxNetAdpNetdevOps;
+#else /* RTLNX_VER_MAX(2,6,29) */
+ pNetDev->open = vboxNetAdpLinuxOpen;
+ pNetDev->stop = vboxNetAdpLinuxStop;
+ pNetDev->hard_start_xmit = vboxNetAdpLinuxXmit;
+ pNetDev->get_stats = vboxNetAdpLinuxGetStats;
+#endif /* RTLNX_VER_MAX(2,6,29) */
+#if RTLNX_VER_MIN(4,10,0)
+ pNetDev->max_mtu = 65536;
+ pNetDev->features = NETIF_F_TSO
+ | NETIF_F_TSO6
+ | NETIF_F_TSO_ECN
+ | NETIF_F_SG
+ | NETIF_F_HW_CSUM;
+#endif /* RTLNX_VER_MIN(4,10,0) */
+
+ pNetDev->ethtool_ops = &gEthToolOpsVBoxNetAdp;
+
+ pPriv = netdev_priv(pNetDev);
+ memset(pPriv, 0, sizeof(*pPriv));
+}
+
+
+int vboxNetAdpOsCreate(PVBOXNETADP pThis, PCRTMAC pMACAddress)
+{
+ int rc = VINF_SUCCESS;
+ struct net_device *pNetDev;
+
+ /* No need for private data. */
+ pNetDev = alloc_netdev(sizeof(VBOXNETADPPRIV),
+ pThis->szName[0] ? pThis->szName : VBOXNETADP_LINUX_NAME,
+#if RTLNX_VER_MIN(3,17,0)
+ NET_NAME_UNKNOWN,
+#endif
+ vboxNetAdpNetDevInit);
+ if (pNetDev)
+ {
+ int err;
+
+ if (pNetDev->dev_addr)
+ {
+ VBOX_DEV_ADDR_SET(pNetDev, pMACAddress, ETH_ALEN);
+ Log2(("vboxNetAdpOsCreate: pNetDev->dev_addr = %.6Rhxd\n", pNetDev->dev_addr));
+
+ /*
+ * We treat presence of VBoxNetFlt filter as our "carrier",
+ * see vboxNetFltSetLinkState().
+ *
+ * operstates.txt: "On device allocation, networking core
+ * sets the flags equivalent to netif_carrier_ok() and
+ * !netif_dormant()" - so turn carrier off here.
+ */
+ netif_carrier_off(pNetDev);
+
+ err = register_netdev(pNetDev);
+ if (!err)
+ {
+ strncpy(pThis->szName, pNetDev->name, sizeof(pThis->szName));
+ pThis->szName[sizeof(pThis->szName) - 1] = '\0';
+ pThis->u.s.pNetDev = pNetDev;
+ Log2(("vboxNetAdpOsCreate: pThis=%p pThis->szName = %p\n", pThis, pThis->szName));
+ return VINF_SUCCESS;
+ }
+ }
+ else
+ {
+ LogRel(("VBoxNetAdp: failed to set MAC address (dev->dev_addr == NULL)\n"));
+ err = EFAULT;
+ }
+ free_netdev(pNetDev);
+ rc = RTErrConvertFromErrno(err);
+ }
+ return rc;
+}
+
+void vboxNetAdpOsDestroy(PVBOXNETADP pThis)
+{
+ struct net_device *pNetDev = pThis->u.s.pNetDev;
+ AssertPtr(pThis->u.s.pNetDev);
+
+ pThis->u.s.pNetDev = NULL;
+ unregister_netdev(pNetDev);
+ free_netdev(pNetDev);
+}
+
+/**
+ * Device open. Called on open /dev/vboxnetctl
+ *
+ * @param pInode Pointer to inode info structure.
+ * @param pFilp Associated file pointer.
+ */
+static int VBoxNetAdpLinuxOpen(struct inode *pInode, struct file *pFilp)
+{
+ Log(("VBoxNetAdpLinuxOpen: pid=%d/%d %s\n", RTProcSelf(), current->pid, current->comm));
+
+#ifdef VBOX_WITH_HARDENING
+ /*
+ * Only root is allowed to access the device, enforce it!
+ */
+ if (!capable(CAP_SYS_ADMIN))
+ {
+ Log(("VBoxNetAdpLinuxOpen: admin privileges required!\n"));
+ return -EPERM;
+ }
+#endif
+
+ return 0;
+}
+
+
+/**
+ * Close device.
+ *
+ * @param pInode Pointer to inode info structure.
+ * @param pFilp Associated file pointer.
+ */
+static int VBoxNetAdpLinuxClose(struct inode *pInode, struct file *pFilp)
+{
+ Log(("VBoxNetAdpLinuxClose: pid=%d/%d %s\n",
+ RTProcSelf(), current->pid, current->comm));
+ pFilp->private_data = NULL;
+ return 0;
+}
+
+/**
+ * Device I/O Control entry point.
+ *
+ * @param pFilp Associated file pointer.
+ * @param uCmd The function specified to ioctl().
+ * @param ulArg The argument specified to ioctl().
+ */
+#if RTLNX_VER_MAX(2,6,36)
+static int VBoxNetAdpLinuxIOCtl(struct inode *pInode, struct file *pFilp,
+ unsigned int uCmd, unsigned long ulArg)
+#else /* RTLNX_VER_MIN(2,6,36) */
+static long VBoxNetAdpLinuxIOCtlUnlocked(struct file *pFilp,
+ unsigned int uCmd, unsigned long ulArg)
+#endif /* RTLNX_VER_MIN(2,6,36) */
+{
+ VBOXNETADPREQ Req;
+ PVBOXNETADP pAdp;
+ int rc;
+ char *pszName = NULL;
+
+ Log(("VBoxNetAdpLinuxIOCtl: param len %#x; uCmd=%#x; add=%#x\n", _IOC_SIZE(uCmd), uCmd, VBOXNETADP_CTL_ADD));
+ if (RT_UNLIKELY(_IOC_SIZE(uCmd) != sizeof(Req))) /* paranoia */
+ {
+ Log(("VBoxNetAdpLinuxIOCtl: bad ioctl sizeof(Req)=%#x _IOC_SIZE=%#x; uCmd=%#x.\n", sizeof(Req), _IOC_SIZE(uCmd), uCmd));
+ return -EINVAL;
+ }
+
+ switch (uCmd)
+ {
+ case VBOXNETADP_CTL_ADD:
+ Log(("VBoxNetAdpLinuxIOCtl: _IOC_DIR(uCmd)=%#x; IOC_OUT=%#x\n", _IOC_DIR(uCmd), IOC_OUT));
+ if (RT_UNLIKELY(copy_from_user(&Req, (void *)ulArg, sizeof(Req))))
+ {
+ Log(("VBoxNetAdpLinuxIOCtl: copy_from_user(,%#lx,) failed; uCmd=%#x.\n", ulArg, uCmd));
+ return -EFAULT;
+ }
+ Log(("VBoxNetAdpLinuxIOCtl: Add %s\n", Req.szName));
+
+ if (Req.szName[0])
+ {
+ pAdp = vboxNetAdpFindByName(Req.szName);
+ if (pAdp)
+ {
+ Log(("VBoxNetAdpLinuxIOCtl: '%s' already exists\n", Req.szName));
+ return -EINVAL;
+ }
+ pszName = Req.szName;
+ }
+ rc = vboxNetAdpCreate(&pAdp, pszName);
+ if (RT_FAILURE(rc))
+ {
+ Log(("VBoxNetAdpLinuxIOCtl: vboxNetAdpCreate -> %Rrc\n", rc));
+ return -(rc == VERR_OUT_OF_RESOURCES ? ENOMEM : EINVAL);
+ }
+
+ Assert(strlen(pAdp->szName) < sizeof(Req.szName));
+ strncpy(Req.szName, pAdp->szName, sizeof(Req.szName) - 1);
+ Req.szName[sizeof(Req.szName) - 1] = '\0';
+
+ if (RT_UNLIKELY(copy_to_user((void *)ulArg, &Req, sizeof(Req))))
+ {
+ /* this is really bad! */
+ /** @todo remove the adapter again? */
+ printk(KERN_ERR "VBoxNetAdpLinuxIOCtl: copy_to_user(%#lx,,%#zx); uCmd=%#x!\n", ulArg, sizeof(Req), uCmd);
+ return -EFAULT;
+ }
+ Log(("VBoxNetAdpLinuxIOCtl: Successfully added '%s'\n", Req.szName));
+ break;
+
+ case VBOXNETADP_CTL_REMOVE:
+ if (RT_UNLIKELY(copy_from_user(&Req, (void *)ulArg, sizeof(Req))))
+ {
+ Log(("VBoxNetAdpLinuxIOCtl: copy_from_user(,%#lx,) failed; uCmd=%#x.\n", ulArg, uCmd));
+ return -EFAULT;
+ }
+ Log(("VBoxNetAdpLinuxIOCtl: Remove %s\n", Req.szName));
+
+ pAdp = vboxNetAdpFindByName(Req.szName);
+ if (!pAdp)
+ {
+ Log(("VBoxNetAdpLinuxIOCtl: '%s' not found\n", Req.szName));
+ return -EINVAL;
+ }
+
+ rc = vboxNetAdpDestroy(pAdp);
+ if (RT_FAILURE(rc))
+ {
+ Log(("VBoxNetAdpLinuxIOCtl: vboxNetAdpDestroy('%s') -> %Rrc\n", Req.szName, rc));
+ return -EINVAL;
+ }
+ Log(("VBoxNetAdpLinuxIOCtl: Successfully removed '%s'\n", Req.szName));
+ break;
+
+ default:
+ printk(KERN_ERR "VBoxNetAdpLinuxIOCtl: unknown command %x.\n", uCmd);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int vboxNetAdpOsInit(PVBOXNETADP pThis)
+{
+ /*
+ * Init linux-specific members.
+ */
+ pThis->u.s.pNetDev = NULL;
+
+ return VINF_SUCCESS;
+}
+
+
+
+/**
+ * Initialize module.
+ *
+ * @returns appropriate status code.
+ */
+static int __init VBoxNetAdpLinuxInit(void)
+{
+ int rc;
+ /*
+ * Initialize IPRT.
+ */
+ rc = RTR0Init(0);
+ if (RT_SUCCESS(rc))
+ {
+ Log(("VBoxNetAdpLinuxInit\n"));
+
+ rc = vboxNetAdpInit();
+ if (RT_SUCCESS(rc))
+ {
+ rc = misc_register(&g_CtlDev);
+ if (rc)
+ {
+ printk(KERN_ERR "VBoxNetAdp: Can't register " VBOXNETADP_CTL_DEV_NAME " device! rc=%d\n", rc);
+ return rc;
+ }
+ LogRel(("VBoxNetAdp: Successfully started.\n"));
+ return 0;
+ }
+ else
+ LogRel(("VBoxNetAdp: failed to register vboxnet0 device (rc=%d)\n", rc));
+ }
+ else
+ LogRel(("VBoxNetAdp: failed to initialize IPRT (rc=%d)\n", rc));
+
+ return -RTErrConvertToErrno(rc);
+}
+
+
+/**
+ * Unload the module.
+ *
+ * @todo We have to prevent this if we're busy!
+ */
+static void __exit VBoxNetAdpLinuxUnload(void)
+{
+ Log(("VBoxNetAdpLinuxUnload\n"));
+
+ /*
+ * Undo the work done during start (in reverse order).
+ */
+
+ vboxNetAdpShutdown();
+ /* Remove control device */
+ misc_deregister(&g_CtlDev);
+
+ RTR0Term();
+
+ Log(("VBoxNetAdpLinuxUnload - done\n"));
+}
+
diff --git a/src/VBox/HostDrivers/VBoxNetAdp/linux/files_vboxnetadp b/src/VBox/HostDrivers/VBoxNetAdp/linux/files_vboxnetadp
new file mode 100755
index 00000000..4cc6510f
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetAdp/linux/files_vboxnetadp
@@ -0,0 +1,112 @@
+#!/bin/sh
+# $Id: files_vboxnetadp $
+## @files
+# Shared file between Makefile.kmk and export_modules.sh.
+#
+
+#
+# Copyright (C) 2009-2022 Oracle and/or its affiliates.
+#
+# This file is part of VirtualBox base platform packages, as
+# available from https://www.virtualbox.org.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation, in version 3 of the
+# License.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses>.
+#
+# The contents of this file may alternatively be used under the terms
+# of the Common Development and Distribution License Version 1.0
+# (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+# in the VirtualBox distribution, in which case the provisions of the
+# CDDL are applicable instead of those of the GPL.
+#
+# You may elect to license modified versions of this file under the
+# terms and conditions of either the GPL or the CDDL or both.
+#
+# SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+#
+
+VBOX_VBOXNETADP_SOURCES=" \
+ ${PATH_ROOT}/include/iprt/alloc.h=>include/iprt/alloc.h \
+ ${PATH_ROOT}/include/iprt/alloca.h=>include/iprt/alloca.h \
+ ${PATH_ROOT}/include/iprt/asm.h=>include/iprt/asm.h \
+ ${PATH_ROOT}/include/iprt/asm-amd64-x86.h=>include/iprt/asm-amd64-x86.h \
+ ${PATH_ROOT}/include/iprt/asm-math.h=>include/iprt/asm-math.h \
+ ${PATH_ROOT}/include/iprt/assert.h=>include/iprt/assert.h \
+ ${PATH_ROOT}/include/iprt/assertcompile.h=>include/iprt/assertcompile.h \
+ ${PATH_ROOT}/include/iprt/avl.h=>include/iprt/avl.h \
+ ${PATH_ROOT}/include/iprt/cdefs.h=>include/iprt/cdefs.h \
+ ${PATH_ROOT}/include/iprt/cpuset.h=>include/iprt/cpuset.h \
+ ${PATH_ROOT}/include/iprt/ctype.h=>include/iprt/ctype.h \
+ ${PATH_ROOT}/include/iprt/err.h=>include/iprt/err.h \
+ ${PATH_ROOT}/include/iprt/errcore.h=>include/iprt/errcore.h \
+ ${PATH_ROOT}/include/iprt/heap.h=>include/iprt/heap.h \
+ ${PATH_ROOT}/include/iprt/initterm.h=>include/iprt/initterm.h \
+ ${PATH_ROOT}/include/iprt/latin1.h=>include/iprt/latin1.h \
+ ${PATH_ROOT}/include/iprt/log.h=>include/iprt/log.h \
+ ${PATH_ROOT}/include/iprt/mangling.h=>include/iprt/mangling.h \
+ ${PATH_ROOT}/include/iprt/mem.h=>include/iprt/mem.h \
+ ${PATH_ROOT}/include/iprt/memobj.h=>include/iprt/memobj.h \
+ ${PATH_ROOT}/include/iprt/mp.h=>include/iprt/mp.h \
+ ${PATH_ROOT}/include/iprt/net.h=>include/iprt/net.h \
+ ${PATH_ROOT}/include/iprt/param.h=>include/iprt/param.h \
+ ${PATH_ROOT}/include/iprt/power.h=>include/iprt/power.h \
+ ${PATH_ROOT}/include/iprt/process.h=>include/iprt/process.h \
+ ${PATH_ROOT}/include/iprt/semaphore.h=>include/iprt/semaphore.h \
+ ${PATH_ROOT}/include/iprt/spinlock.h=>include/iprt/spinlock.h \
+ ${PATH_ROOT}/include/iprt/stdarg.h=>include/iprt/stdarg.h \
+ ${PATH_ROOT}/include/iprt/stdint.h=>include/iprt/stdint.h \
+ ${PATH_ROOT}/include/iprt/string.h=>include/iprt/string.h \
+ ${PATH_ROOT}/include/iprt/thread.h=>include/iprt/thread.h \
+ ${PATH_ROOT}/include/iprt/time.h=>include/iprt/time.h \
+ ${PATH_ROOT}/include/iprt/timer.h=>include/iprt/timer.h \
+ ${PATH_ROOT}/include/iprt/types.h=>include/iprt/types.h \
+ ${PATH_ROOT}/include/iprt/uint64.h=>include/iprt/uint64.h \
+ ${PATH_ROOT}/include/iprt/uni.h=>include/iprt/uni.h \
+ ${PATH_ROOT}/include/iprt/utf16.h=>include/iprt/utf16.h \
+ ${PATH_ROOT}/include/iprt/uuid.h=>include/iprt/uuid.h \
+ ${PATH_ROOT}/include/iprt/x86.h=>include/iprt/x86.h \
+ ${PATH_ROOT}/include/iprt/x86-helpers.h=>include/iprt/x86-helpers.h \
+ ${PATH_ROOT}/include/iprt/linux/version.h=>include/iprt/linux/version.h \
+ ${PATH_ROOT}/include/iprt/nocrt/limits.h=>include/iprt/nocrt/limits.h \
+ ${PATH_ROOT}/include/VBox/cdefs.h=>include/VBox/cdefs.h \
+ ${PATH_ROOT}/include/VBox/err.h=>include/VBox/err.h \
+ ${PATH_ROOT}/include/VBox/log.h=>include/VBox/log.h \
+ ${PATH_ROOT}/include/VBox/intnet.h=>include/VBox/intnet.h \
+ ${PATH_ROOT}/include/VBox/vmm/stam.h=>include/VBox/vmm/stam.h \
+ ${PATH_ROOT}/include/VBox/sup.h=>include/VBox/sup.h \
+ ${PATH_ROOT}/include/VBox/types.h=>include/VBox/types.h \
+ ${PATH_ROOT}/include/VBox/SUPDrvMangling.h=>include/VBox/SUPDrvMangling.h \
+ ${PATH_ROOT}/src/VBox/HostDrivers/VBoxNetAdp/linux/VBoxNetAdp-linux.c=>linux/VBoxNetAdp-linux.c \
+ ${PATH_ROOT}/src/VBox/HostDrivers/VBoxNetAdp/VBoxNetAdp.c=>VBoxNetAdp.c \
+ ${PATH_ROOT}/src/VBox/HostDrivers/VBoxNetAdp/VBoxNetAdpInternal.h=>VBoxNetAdpInternal.h \
+ ${PATH_ROOT}/src/VBox/Installer/linux/Makefile-footer.gmk=>Makefile-footer.gmk \
+ ${PATH_ROOT}/src/VBox/Installer/linux/Makefile-header.gmk=>Makefile-header.gmk \
+ ${PATH_ROOT}/src/VBox/Runtime/common/math/gcc/divdi3.c=>math/gcc/divdi3.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/math/gcc/moddi3.c=>math/gcc/moddi3.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/math/gcc/qdivrem.c=>math/gcc/qdivrem.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/math/gcc/quad.h=>math/gcc/quad.h \
+ ${PATH_ROOT}/src/VBox/Runtime/common/math/gcc/udivdi3.c=>math/gcc/udivdi3.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/math/gcc/udivmoddi4.c=>math/gcc/udivmoddi4.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/math/gcc/umoddi3.c=>math/gcc/umoddi3.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/string/strformat.cpp=>common/string/strformat.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/string/strformatrt.cpp=>common/string/strformatrt.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/string/strformattype.cpp=>common/string/strformattype.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/string/strprintf.cpp=>common/string/strprintf.c \
+ ${PATH_ROOT}/src/VBox/Runtime/common/string/strtonum.cpp=>common/string/strtonum.c \
+ ${PATH_ROOT}/src/VBox/Runtime/include/internal/iprt.h=>include/internal/iprt.h \
+ ${PATH_ROOT}/src/VBox/Runtime/r0drv/linux/the-linux-kernel.h=>r0drv/linux/the-linux-kernel.h \
+ ${PATH_OUT}/version-generated.h=>version-generated.h \
+ ${PATH_OUT}/revision-generated.h=>revision-generated.h \
+ ${PATH_OUT}/product-generated.h=>product-generated.h \
+"
+
diff --git a/src/VBox/HostDrivers/VBoxNetAdp/solaris/VBoxNetAdp-solaris.c b/src/VBox/HostDrivers/VBoxNetAdp/solaris/VBoxNetAdp-solaris.c
new file mode 100644
index 00000000..3fd429d1
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetAdp/solaris/VBoxNetAdp-solaris.c
@@ -0,0 +1,581 @@
+/* $Id: VBoxNetAdp-solaris.c $ */
+/** @file
+ * VBoxNetAdapter - Network Adapter Driver (Host), Solaris Specific Code.
+ */
+
+/*
+ * Copyright (C) 2009-2022 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+
+/*********************************************************************************************************************************
+* Header Files *
+*********************************************************************************************************************************/
+#define LOG_GROUP LOG_GROUP_NET_ADP_DRV
+#include <VBox/log.h>
+#include <iprt/errcore.h>
+#include <VBox/version.h>
+#include <iprt/assert.h>
+#include <iprt/semaphore.h>
+#include <iprt/initterm.h>
+#include <iprt/assert.h>
+#include <iprt/mem.h>
+#include <iprt/rand.h>
+
+#include <sys/types.h>
+#include <sys/dlpi.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/stat.h>
+#include <sys/stream.h>
+#include <sys/stropts.h>
+#include <sys/strsun.h>
+#include <sys/modctl.h>
+#include <sys/ddi.h>
+#include <sys/sunddi.h>
+#include <sys/sunldi.h>
+#include <sys/gld.h>
+
+#include "../VBoxNetAdpInternal.h"
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+#define DEVICE_NAME "vboxnet"
+/** The module descriptions as seen in 'modinfo'. */
+#define DEVICE_DESC_DRV "VirtualBox NetAdp"
+/** The maximum MTU size permittable, value taken from "Oracle Quad 10 Gb or Dual 40
+ * Gb Ethernet Adapter User's Guide". */
+#define DEVICE_MAX_MTU_SIZE 9706
+
+
+/*********************************************************************************************************************************
+* Internal Functions *
+*********************************************************************************************************************************/
+static int VBoxNetAdpSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd);
+static int VBoxNetAdpSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd);
+static int VBoxNetAdpSolarisQuiesceNotNeeded(dev_info_t *pDip);
+
+/**
+ * Streams: module info.
+ */
+static struct module_info g_VBoxNetAdpSolarisModInfo =
+{
+ 0x0dd, /* module id */
+ DEVICE_NAME,
+ 0, /* min. packet size */
+ INFPSZ, /* max. packet size */
+ 0, /* hi-water mark */
+ 0 /* lo-water mark */
+};
+
+/**
+ * Streams: read queue hooks.
+ */
+static struct qinit g_VBoxNetAdpSolarisReadQ =
+{
+ NULL, /* read */
+ gld_rsrv,
+ gld_open,
+ gld_close,
+ NULL, /* admin (reserved) */
+ &g_VBoxNetAdpSolarisModInfo,
+ NULL /* module stats */
+};
+
+/**
+ * Streams: write queue hooks.
+ */
+static struct qinit g_VBoxNetAdpSolarisWriteQ =
+{
+ gld_wput,
+ gld_wsrv,
+ NULL, /* open */
+ NULL, /* close */
+ NULL, /* admin (reserved) */
+ &g_VBoxNetAdpSolarisModInfo,
+ NULL /* module stats */
+};
+
+/**
+ * Streams: IO stream tab.
+ */
+static struct streamtab g_VBoxNetAdpSolarisStreamTab =
+{
+ &g_VBoxNetAdpSolarisReadQ,
+ &g_VBoxNetAdpSolarisWriteQ,
+ NULL, /* muxread init */
+ NULL /* muxwrite init */
+};
+
+/**
+ * cb_ops: driver char/block entry points
+ */
+static struct cb_ops g_VBoxNetAdpSolarisCbOps =
+{
+ nulldev, /* cb open */
+ nulldev, /* cb close */
+ nodev, /* b strategy */
+ nodev, /* b dump */
+ nodev, /* b print */
+ nodev, /* cb read */
+ nodev, /* cb write */
+ nodev, /* cb ioctl */
+ nodev, /* c devmap */
+ nodev, /* c mmap */
+ nodev, /* c segmap */
+ nochpoll, /* c poll */
+ ddi_prop_op, /* property ops */
+ &g_VBoxNetAdpSolarisStreamTab,
+ D_MP, /* compat. flag */
+ CB_REV /* revision */
+};
+
+/**
+ * dev_ops: driver entry/exit and other ops.
+ */
+static struct dev_ops g_VBoxNetAdpSolarisDevOps =
+{
+ DEVO_REV, /* driver build revision */
+ 0, /* ref count */
+ gld_getinfo,
+ nulldev, /* identify */
+ nulldev, /* probe */
+ VBoxNetAdpSolarisAttach,
+ VBoxNetAdpSolarisDetach,
+ nodev, /* reset */
+ &g_VBoxNetAdpSolarisCbOps,
+ (struct bus_ops *)0,
+ nodev, /* power */
+ VBoxNetAdpSolarisQuiesceNotNeeded
+};
+
+/**
+ * modldrv: export driver specifics to kernel
+ */
+static struct modldrv g_VBoxNetAdpSolarisDriver =
+{
+ &mod_driverops, /* extern from kernel */
+ DEVICE_DESC_DRV " " VBOX_VERSION_STRING "r" RT_XSTR(VBOX_SVN_REV),
+ &g_VBoxNetAdpSolarisDevOps
+};
+
+/**
+ * modlinkage: export install/remove/info to the kernel
+ */
+static struct modlinkage g_VBoxNetAdpSolarisModLinkage =
+{
+ MODREV_1, /* loadable module system revision */
+ {
+ &g_VBoxNetAdpSolarisDriver, /* adapter streams driver framework */
+ NULL /* terminate array of linkage structures */
+ }
+};
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+/** The default ethernet broadcast address */
+static uchar_t achBroadcastAddr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+
+/**
+ * vboxnetadp_state_t: per-instance data
+ */
+typedef struct vboxnetadp_state_t
+{
+ dev_info_t *pDip; /* device info. */
+ RTMAC FactoryMac; /* default 'factory' MAC address */
+ RTMAC CurrentMac; /* current MAC address */
+} vboxnetadp_state_t;
+
+
+/*********************************************************************************************************************************
+* Internal Functions *
+*********************************************************************************************************************************/
+static int vboxNetAdpSolarisGenerateMac(PRTMAC pMac);
+static int vboxNetAdpSolarisSetMacAddress(gld_mac_info_t *pMacInfo, unsigned char *pszMacAddr);
+static int vboxNetAdpSolarisSend(gld_mac_info_t *pMacInfo, mblk_t *pMsg);
+static int vboxNetAdpSolarisStub(gld_mac_info_t *pMacInfo);
+static int vboxNetAdpSolarisSetPromisc(gld_mac_info_t *pMacInfo, int fPromisc);
+static int vboxNetAdpSolarisSetMulticast(gld_mac_info_t *pMacInfo, unsigned char *pMulticastAddr, int fMulticast);
+static int vboxNetAdpSolarisGetStats(gld_mac_info_t *pMacInfo, struct gld_stats *pStats);
+
+
+/**
+ * Kernel entry points
+ */
+int _init(void)
+{
+ LogFunc((DEVICE_NAME ":_init\n"));
+
+ /*
+ * Prevent module autounloading.
+ */
+ modctl_t *pModCtl = mod_getctl(&g_VBoxNetAdpSolarisModLinkage);
+ if (pModCtl)
+ pModCtl->mod_loadflags |= MOD_NOAUTOUNLOAD;
+ else
+ LogRel((DEVICE_NAME ":failed to disable autounloading!\n"));
+
+ /*
+ * Initialize IPRT.
+ */
+ int rc = RTR0Init(0);
+ if (RT_SUCCESS(rc))
+ {
+ rc = mod_install(&g_VBoxNetAdpSolarisModLinkage);
+ if (!rc)
+ return rc;
+
+ LogRel((DEVICE_NAME ":mod_install failed. rc=%d\n", rc));
+ RTR0Term();
+ }
+ else
+ LogRel((DEVICE_NAME ":failed to initialize IPRT (rc=%d)\n", rc));
+
+ return RTErrConvertToErrno(rc);
+}
+
+
+int _fini(void)
+{
+ LogFunc((DEVICE_NAME ":_fini\n"));
+
+ /*
+ * Undo the work done during start (in reverse order).
+ */
+ int rc = mod_remove(&g_VBoxNetAdpSolarisModLinkage);
+ if (!rc)
+ RTR0Term();
+
+ return rc;
+}
+
+
+int _info(struct modinfo *pModInfo)
+{
+ LogFunc((DEVICE_NAME ":_info\n"));
+
+ int rc = mod_info(&g_VBoxNetAdpSolarisModLinkage, pModInfo);
+
+ Log((DEVICE_NAME ":_info returns %d\n", rc));
+ return rc;
+}
+
+
+/**
+ * Attach entry point, to attach a device to the system or resume it.
+ *
+ * @param pDip The module structure instance.
+ * @param enmCmd Operation type (attach/resume).
+ *
+ * @returns corresponding solaris error code.
+ */
+static int VBoxNetAdpSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd)
+{
+ LogFunc((DEVICE_NAME ":VBoxNetAdpSolarisAttach pDip=%p enmCmd=%d\n", pDip, enmCmd));
+
+ int rc = -1;
+ switch (enmCmd)
+ {
+ case DDI_ATTACH:
+ {
+ gld_mac_info_t *pMacInfo = gld_mac_alloc(pDip);
+ if (pMacInfo)
+ {
+ vboxnetadp_state_t *pState = RTMemAllocZ(sizeof(vboxnetadp_state_t));
+ if (pState)
+ {
+ pState->pDip = pDip;
+
+ /*
+ * Setup GLD MAC layer registration info.
+ */
+ pMacInfo->gldm_reset = vboxNetAdpSolarisStub;
+ pMacInfo->gldm_start = vboxNetAdpSolarisStub;
+ pMacInfo->gldm_stop = vboxNetAdpSolarisStub;
+ pMacInfo->gldm_set_mac_addr = vboxNetAdpSolarisSetMacAddress;
+ pMacInfo->gldm_set_multicast = vboxNetAdpSolarisSetMulticast;
+ pMacInfo->gldm_set_promiscuous = vboxNetAdpSolarisSetPromisc;
+ pMacInfo->gldm_send = vboxNetAdpSolarisSend;
+ pMacInfo->gldm_intr = NULL;
+ pMacInfo->gldm_get_stats = vboxNetAdpSolarisGetStats;
+ pMacInfo->gldm_ioctl = NULL;
+ pMacInfo->gldm_ident = DEVICE_NAME;
+ pMacInfo->gldm_type = DL_ETHER;
+ pMacInfo->gldm_minpkt = 0;
+ pMacInfo->gldm_maxpkt = DEVICE_MAX_MTU_SIZE;
+ pMacInfo->gldm_capabilities = GLD_CAP_LINKSTATE;
+ AssertCompile(sizeof(RTMAC) == ETHERADDRL);
+
+ pMacInfo->gldm_addrlen = ETHERADDRL;
+ pMacInfo->gldm_saplen = -2;
+ pMacInfo->gldm_broadcast_addr = achBroadcastAddr;
+ pMacInfo->gldm_ppa = ddi_get_instance(pState->pDip);
+ pMacInfo->gldm_devinfo = pState->pDip;
+ pMacInfo->gldm_private = (caddr_t)pState;
+
+ /*
+ * We use a semi-random MAC addresses similar to a guest NIC's MAC address
+ * as the default factory address of the interface.
+ */
+ rc = vboxNetAdpSolarisGenerateMac(&pState->FactoryMac);
+ if (RT_SUCCESS(rc))
+ {
+ bcopy(&pState->FactoryMac, &pState->CurrentMac, sizeof(RTMAC));
+ pMacInfo->gldm_vendor_addr = (unsigned char *)&pState->FactoryMac;
+
+ /*
+ * Now try registering our GLD with the MAC layer.
+ * Registration can fail on some S10 versions when the MTU size is more than 1500.
+ * When we implement jumbo frames we should probably retry with MTU 1500 for S10.
+ */
+ rc = gld_register(pDip, (char *)ddi_driver_name(pDip), pMacInfo);
+ if (rc == DDI_SUCCESS)
+ {
+ ddi_report_dev(pDip);
+ gld_linkstate(pMacInfo, GLD_LINKSTATE_UP);
+ return DDI_SUCCESS;
+ }
+ else
+ LogRel((DEVICE_NAME ":VBoxNetAdpSolarisAttach failed to register GLD. rc=%d\n", rc));
+ }
+ else
+ LogRel((DEVICE_NAME ":VBoxNetAdpSolarisAttach failed to generate mac address.rc=%d\n"));
+
+ RTMemFree(pState);
+ }
+ else
+ LogRel((DEVICE_NAME ":VBoxNetAdpSolarisAttach failed to alloc state.\n"));
+
+ gld_mac_free(pMacInfo);
+ }
+ else
+ LogRel((DEVICE_NAME ":VBoxNetAdpSolarisAttach failed to alloc mac structure.\n"));
+ return DDI_FAILURE;
+ }
+
+ case DDI_RESUME:
+ {
+ /* Nothing to do here... */
+ return DDI_SUCCESS;
+ }
+
+ /* case DDI_PM_RESUME: */
+ default:
+ return DDI_FAILURE;
+ }
+}
+
+
+/**
+ * Detach entry point, to detach a device to the system or suspend it.
+ *
+ * @param pDip The module structure instance.
+ * @param enmCmd Operation type (detach/suspend).
+ *
+ * @returns corresponding solaris error code.
+ */
+static int VBoxNetAdpSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd)
+{
+ LogFunc((DEVICE_NAME ":VBoxNetAdpSolarisDetach pDip=%p enmCmd=%d\n", pDip, enmCmd));
+
+ switch (enmCmd)
+ {
+ case DDI_DETACH:
+ {
+ /*
+ * Unregister and clean up.
+ */
+ gld_mac_info_t *pMacInfo = ddi_get_driver_private(pDip);
+ if (pMacInfo)
+ {
+ vboxnetadp_state_t *pState = (vboxnetadp_state_t *)pMacInfo->gldm_private;
+ if (pState)
+ {
+ gld_linkstate(pMacInfo, GLD_LINKSTATE_DOWN);
+ int rc = gld_unregister(pMacInfo);
+ if (rc == DDI_SUCCESS)
+ {
+ gld_mac_free(pMacInfo);
+ RTMemFree(pState);
+ return DDI_SUCCESS;
+ }
+ else
+ LogRel((DEVICE_NAME ":VBoxNetAdpSolarisDetach failed to unregister GLD from MAC layer.rc=%d\n", rc));
+ }
+ else
+ LogRel((DEVICE_NAME ":VBoxNetAdpSolarisDetach failed to get internal state.\n"));
+ }
+ else
+ LogRel((DEVICE_NAME ":VBoxNetAdpSolarisDetach failed to get driver private GLD data.\n"));
+
+ return DDI_FAILURE;
+ }
+
+ case DDI_RESUME:
+ {
+ /* Nothing to do here... */
+ return DDI_SUCCESS;
+ }
+
+ /* case DDI_SUSPEND: */
+ /* case DDI_HOTPLUG_DETACH: */
+ default:
+ return DDI_FAILURE;
+ }
+}
+
+
+/**
+ * Quiesce not-needed entry point, as Solaris 10 doesn't have any
+ * ddi_quiesce_not_needed() function.
+ *
+ * @param pDip The module structure instance.
+ *
+ * @return corresponding solaris error code.
+ */
+static int VBoxNetAdpSolarisQuiesceNotNeeded(dev_info_t *pDip)
+{
+ return DDI_SUCCESS;
+}
+
+
+static int vboxNetAdpSolarisGenerateMac(PRTMAC pMac)
+{
+ pMac->au8[0] = 0x08;
+ pMac->au8[1] = 0x00;
+ pMac->au8[2] = 0x27;
+ RTRandBytes(&pMac->au8[3], 3);
+ Log((DEVICE_NAME ":VBoxNetAdpSolarisGenerateMac Generated %.*Rhxs\n", sizeof(RTMAC), &pMac));
+ return VINF_SUCCESS;
+}
+
+
+static int vboxNetAdpSolarisSetMacAddress(gld_mac_info_t *pMacInfo, unsigned char *pszMacAddr)
+{
+ vboxnetadp_state_t *pState = (vboxnetadp_state_t *)pMacInfo->gldm_private;
+ if (pState)
+ {
+ bcopy(pszMacAddr, &pState->CurrentMac, sizeof(RTMAC));
+ Log((DEVICE_NAME ":vboxNetAdpSolarisSetMacAddress updated MAC %.*Rhxs\n", sizeof(RTMAC), &pState->CurrentMac));
+ return GLD_SUCCESS;
+ }
+ else
+ LogRel((DEVICE_NAME ":vboxNetAdpSolarisSetMacAddress failed to get internal state.\n"));
+ return GLD_FAILURE;
+}
+
+
+static int vboxNetAdpSolarisSend(gld_mac_info_t *pMacInfo, mblk_t *pMsg)
+{
+ while (pMsg)
+ {
+ mblk_t *pMsgNext = pMsg->b_cont;
+ pMsg->b_cont = NULL;
+ freemsg(pMsg);
+ pMsg = pMsgNext;
+ }
+ return GLD_SUCCESS;
+}
+
+
+static int vboxNetAdpSolarisStub(gld_mac_info_t *pMacInfo)
+{
+ return GLD_SUCCESS;
+}
+
+
+static int vboxNetAdpSolarisSetMulticast(gld_mac_info_t *pMacInfo, unsigned char *pMulticastAddr, int fMulticast)
+{
+ return GLD_SUCCESS;
+}
+
+
+static int vboxNetAdpSolarisSetPromisc(gld_mac_info_t *pMacInfo, int fPromisc)
+{
+ /* Host requesting promiscuous intnet connection... */
+ return GLD_SUCCESS;
+}
+
+
+static int vboxNetAdpSolarisGetStats(gld_mac_info_t *pMacInfo, struct gld_stats *pStats)
+{
+ /*
+ * For now fake up stats. Stats like duplex and speed are better set as they
+ * are used in utilities like dladm. Link state capabilities are critical
+ * as they are used by ipadm while trying to restore persistent interface configs.
+ */
+ vboxnetadp_state_t *pState = (vboxnetadp_state_t *)pMacInfo->gldm_private;
+ if (pState)
+ {
+ pStats->glds_speed = 1000000000ULL; /* Bits/sec. */
+ pStats->glds_media = GLDM_UNKNOWN; /* Media/Connector Type */
+ pStats->glds_intr = 0; /* Interrupt count */
+ pStats->glds_norcvbuf = 0; /* Recv. discards */
+ pStats->glds_errxmt = 0; /* Xmit errors */
+ pStats->glds_errrcv = 0; /* Recv. errors */
+ pStats->glds_missed = 0; /* Pkt Drops on Recv. */
+ pStats->glds_underflow = 0; /* Buffer underflows */
+ pStats->glds_overflow = 0; /* Buffer overflows */
+
+ /* Ether */
+ pStats->glds_frame = 0; /* Align errors */
+ pStats->glds_crc = 0; /* CRC errors */
+ pStats->glds_duplex = GLD_DUPLEX_FULL; /* Link duplex state */
+ pStats->glds_nocarrier = 0; /* Carrier sense errors */
+ pStats->glds_collisions = 0; /* Xmit Collisions */
+ pStats->glds_excoll = 0; /* Frame discard due to excess collisions */
+ pStats->glds_xmtlatecoll = 0; /* Late collisions */
+ pStats->glds_defer = 0; /* Deferred Xmits */
+ pStats->glds_dot3_first_coll = 0; /* Single collision frames */
+ pStats->glds_dot3_multi_coll = 0; /* Multiple collision frames */
+ pStats->glds_dot3_sqe_error = 0; /* SQE errors */
+ pStats->glds_dot3_mac_xmt_error = 0; /* MAC Xmit errors */
+ pStats->glds_dot3_mac_rcv_error = 0; /* Mac Recv. errors */
+ pStats->glds_dot3_frame_too_long = 0; /* Frame too long errors */
+ pStats->glds_short = 0; /* Runt frames */
+
+ pStats->glds_noxmtbuf = 0; /* Xmit Buf errors */
+ pStats->glds_xmtretry = 0; /* Xmit retries */
+ pStats->glds_multixmt = 0; /* Multicast Xmits */
+ pStats->glds_multircv = 0; /* Multicast Recvs. */
+ pStats->glds_brdcstxmt = 0; /* Broadcast Xmits*/
+ pStats->glds_brdcstrcv = 0; /* Broadcast Recvs. */
+
+ return GLD_SUCCESS;
+ }
+ else
+ LogRel((DEVICE_NAME ":vboxNetAdpSolarisGetStats failed to get internal state.\n"));
+ return GLD_FAILURE;
+}
+
diff --git a/src/VBox/HostDrivers/VBoxNetAdp/solaris/hostname.vboxnet0 b/src/VBox/HostDrivers/VBoxNetAdp/solaris/hostname.vboxnet0
new file mode 100644
index 00000000..30545bb9
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetAdp/solaris/hostname.vboxnet0
@@ -0,0 +1 @@
+192.168.56.1
diff --git a/src/VBox/HostDrivers/VBoxNetAdp/solaris/vboxnet.conf b/src/VBox/HostDrivers/VBoxNetAdp/solaris/vboxnet.conf
new file mode 100644
index 00000000..9673f12d
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetAdp/solaris/vboxnet.conf
@@ -0,0 +1,43 @@
+# $Id: vboxnet.conf $
+## @file
+# Solaris Host VBoxNet Configuration
+#
+
+#
+# Copyright (C) 2009-2022 Oracle and/or its affiliates.
+#
+# This file is part of VirtualBox base platform packages, as
+# available from https://www.virtualbox.org.
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation, in version 3 of the
+# License.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, see <https://www.gnu.org/licenses>.
+#
+# The contents of this file may alternatively be used under the terms
+# of the Common Development and Distribution License Version 1.0
+# (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+# in the VirtualBox distribution, in which case the provisions of the
+# CDDL are applicable instead of those of the GPL.
+#
+# You may elect to license modified versions of this file under the
+# terms and conditions of either the GPL or the CDDL or both.
+#
+# SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+#
+
+# This needs to go into /platform/i86pc/kernel/drv,
+# while the 64-bit driver object goes into the amd64
+# subdirectory (32-bit drivers goes into the same
+# directory).
+#
+name="vboxnet" parent="pseudo" instance=0;
+
diff --git a/src/VBox/HostDrivers/VBoxNetAdp/win/Makefile.kup b/src/VBox/HostDrivers/VBoxNetAdp/win/Makefile.kup
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetAdp/win/Makefile.kup
diff --git a/src/VBox/HostDrivers/VBoxNetAdp/win/VBoxNetAdp-win.cpp b/src/VBox/HostDrivers/VBoxNetAdp/win/VBoxNetAdp-win.cpp
new file mode 100644
index 00000000..d9804393
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetAdp/win/VBoxNetAdp-win.cpp
@@ -0,0 +1,1888 @@
+/* $Id: VBoxNetAdp-win.cpp $ */
+/** @file
+ * VBoxNetAdp-win.cpp - NDIS6 Host-only Networking Driver, Windows-specific code.
+ */
+/*
+ * Copyright (C) 2014-2022 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+#define LOG_GROUP LOG_GROUP_NET_ADP_DRV
+
+#include <VBox/log.h>
+#include <VBox/version.h>
+#include <VBox/err.h>
+#include <VBox/sup.h>
+#include <VBox/intnet.h>
+#include <VBox/intnetinline.h>
+#include <iprt/assert.h>
+#include <iprt/initterm.h>
+#include <iprt/list.h>
+#include <iprt/net.h>
+#include <iprt/semaphore.h>
+#include <iprt/string.h>
+#include <iprt/uuid.h>
+
+#include <iprt/nt/ntddk.h>
+#include <iprt/nt/ndis.h>
+
+#include "VBoxNetAdp-win.h"
+#include "VBox/VBoxNetCmn-win.h"
+
+#define VBOXNETADP_MEM_TAG 'OHBV'
+
+/*
+ * By default the link speed reported to be 1Gbps. We may wish to lower
+ * it to 100Mbps to work around issues with multi-cast traffic on the host.
+ * See @bugref{6379}.
+ */
+#define VBOXNETADPWIN_LINK_SPEED 1000000000ULL
+
+#define LogError LogRel
+
+/* Forward declarations */
+MINIPORT_INITIALIZE vboxNetAdpWinInitializeEx;
+MINIPORT_HALT vboxNetAdpWinHaltEx;
+MINIPORT_UNLOAD vboxNetAdpWinUnload;
+MINIPORT_PAUSE vboxNetAdpWinPause;
+MINIPORT_RESTART vboxNetAdpWinRestart;
+MINIPORT_OID_REQUEST vboxNetAdpWinOidRequest;
+MINIPORT_SEND_NET_BUFFER_LISTS vboxNetAdpWinSendNetBufferLists;
+MINIPORT_RETURN_NET_BUFFER_LISTS vboxNetAdpWinReturnNetBufferLists;
+MINIPORT_CANCEL_SEND vboxNetAdpWinCancelSend;
+MINIPORT_CHECK_FOR_HANG vboxNetAdpWinCheckForHangEx;
+MINIPORT_RESET vboxNetAdpWinResetEx;
+MINIPORT_DEVICE_PNP_EVENT_NOTIFY vboxNetAdpWinDevicePnPEventNotify;
+MINIPORT_SHUTDOWN vboxNetAdpWinShutdownEx;
+MINIPORT_CANCEL_OID_REQUEST vboxNetAdpWinCancelOidRequest;
+
+
+/* Packet types by destination address; used in statistics. */
+typedef enum {
+ kVBoxNetAdpWinPacketType_Unicast,
+ kVBoxNetAdpWinPacketType_Multicast,
+ kVBoxNetAdpWinPacketType_Broadcast,
+ kVBoxNetAdpWinPacketType_ArraySize /* Must be the last one */
+} VBOXNETADPWIN_PACKET_TYPE;
+
+
+/* Miniport states as defined by NDIS. */
+typedef enum {
+ kVBoxNetAdpWinState_Initializing,
+ kVBoxNetAdpWinState_Paused,
+ kVBoxNetAdpWinState_Restarting,
+ kVBoxNetAdpWinState_Running,
+ kVBoxNetAdpWinState_Pausing,
+ kVBoxNetAdpWinState_32BitHack = 0x7fffffff
+} VBOXNETADPWIN_ADAPTER_STATE;
+
+
+/*
+ * Valid state transitions are:
+ * 1) Disconnected -> Connecting : start the worker thread, attempting to init IDC;
+ * 2) Connecting -> Disconnected : failed to start IDC init worker thread;
+ * 3) Connecting -> Connected : IDC init successful, terminate the worker;
+ * 4) Connecting -> Stopping : IDC init incomplete, but the driver is being unloaded, terminate the worker;
+ * 5) Connected -> Stopping : IDC init was successful, no worker, the driver is being unloaded;
+ *
+ * Driver terminates in either in Disconnected or in Stopping state.
+ */
+typedef enum {
+ kVBoxNetAdpWinIdcState_Disconnected = 0, /* Initial state */
+ kVBoxNetAdpWinIdcState_Connecting, /* Attemping to init IDC, worker thread running */
+ kVBoxNetAdpWinIdcState_Connected, /* Successfully connected to IDC, worker thread terminated */
+ kVBoxNetAdpWinIdcState_Stopping /* Terminating the worker thread and disconnecting IDC */
+} VBOXNETADPWIN_IDC_STATE;
+
+typedef struct _VBOXNETADPGLOBALS
+{
+ /** Miniport driver handle. */
+ NDIS_HANDLE hMiniportDriver;
+ /** Power management capabilities, shared by all instances, do not change after init. */
+ NDIS_PNP_CAPABILITIES PMCaps;
+ /** The INTNET trunk network interface factory. */
+ INTNETTRUNKFACTORY TrunkFactory;
+ /** The SUPDRV component factory registration. */
+ SUPDRVFACTORY SupDrvFactory;
+ /** The SUPDRV IDC handle (opaque struct). */
+ SUPDRVIDCHANDLE SupDrvIDC;
+ /** IDC init thread handle. */
+ HANDLE hInitIdcThread;
+ /** Lock protecting the following members. */
+ NDIS_SPIN_LOCK Lock;
+ /** Lock-protected: the head of module list. */
+ RTLISTANCHOR ListOfAdapters;
+ /** Lock-protected: The number of current factory references. */
+ int32_t volatile cFactoryRefs;
+ /** Lock-protected: IDC initialization state. */
+ volatile uint32_t enmIdcState;
+ /** Lock-protected: event signaled when trunk factory is not in use. */
+ NDIS_EVENT EventUnloadAllowed;
+} VBOXNETADPGLOBALS, *PVBOXNETADPGLOBALS;
+
+/* win-specific global data */
+VBOXNETADPGLOBALS g_VBoxNetAdpGlobals;
+
+
+typedef struct _VBOXNETADP_ADAPTER {
+ /** Auxiliary member to link adapters into a list. */
+ RTLISTNODE node;
+ /** Adapter handle for NDIS. */
+ NDIS_HANDLE hAdapter;
+ /** Memory pool network buffers are allocated from. */
+ NDIS_HANDLE hPool;
+ /** Our RJ-45 port.
+ * This is what the internal network plugs into. */
+ INTNETTRUNKIFPORT MyPort;
+ /** The RJ-45 port on the INTNET "switch".
+ * This is what we're connected to. */
+ PINTNETTRUNKSWPORT pSwitchPort;
+ /** Pointer to global data */
+ PVBOXNETADPGLOBALS pGlobals;
+ /** Adapter state in NDIS, used for assertions only */
+ VBOXNETADPWIN_ADAPTER_STATE volatile enmAdapterState; /// @todo do we need it really?
+ /** The trunk state. */
+ INTNETTRUNKIFSTATE volatile enmTrunkState;
+ /** Number of pending operations, when it reaches zero we signal EventIdle. */
+ int32_t volatile cBusy;
+ /** The event that is signaled when we go idle and that pfnWaitForIdle blocks on. */
+ NDIS_EVENT EventIdle;
+ /** MAC address of adapter. */
+ RTMAC MacAddr;
+ /** Statistics: bytes received from internal network. */
+ uint64_t au64StatsInOctets[kVBoxNetAdpWinPacketType_ArraySize];
+ /** Statistics: packets received from internal network. */
+ uint64_t au64StatsInPackets[kVBoxNetAdpWinPacketType_ArraySize];
+ /** Statistics: bytes sent to internal network. */
+ uint64_t au64StatsOutOctets[kVBoxNetAdpWinPacketType_ArraySize];
+ /** Statistics: packets sent to internal network. */
+ uint64_t au64StatsOutPackets[kVBoxNetAdpWinPacketType_ArraySize];
+ /** Adapter friendly name. */
+ char szName[1];
+} VBOXNETADP_ADAPTER;
+typedef VBOXNETADP_ADAPTER *PVBOXNETADP_ADAPTER;
+
+
+/* Port */
+
+#define IFPORT_2_VBOXNETADP_ADAPTER(pIfPort) \
+ ( (PVBOXNETADP_ADAPTER)((uint8_t *)(pIfPort) - RT_UOFFSETOF(VBOXNETADP_ADAPTER, MyPort)) )
+
+DECLINLINE(VBOXNETADPWIN_ADAPTER_STATE) vboxNetAdpWinGetState(PVBOXNETADP_ADAPTER pThis)
+{
+ return (VBOXNETADPWIN_ADAPTER_STATE)ASMAtomicUoReadU32((uint32_t volatile *)&pThis->enmAdapterState);
+}
+
+DECLINLINE(VBOXNETADPWIN_ADAPTER_STATE) vboxNetAdpWinSetState(PVBOXNETADP_ADAPTER pThis, VBOXNETADPWIN_ADAPTER_STATE enmNewState)
+{
+ return (VBOXNETADPWIN_ADAPTER_STATE)ASMAtomicXchgU32((uint32_t volatile *)&pThis->enmAdapterState, enmNewState);
+}
+
+DECLINLINE(bool) vboxNetAdpWinSetState(PVBOXNETADP_ADAPTER pThis, VBOXNETADPWIN_ADAPTER_STATE enmNewState,
+ VBOXNETADPWIN_ADAPTER_STATE enmOldState)
+{
+ return ASMAtomicCmpXchgU32((uint32_t volatile *)&pThis->enmAdapterState, enmNewState, enmOldState);
+}
+
+#ifdef DEBUG
+
+DECLHIDDEN(void) vboxNetAdpWinDumpPackets(const char *pszMsg, PNET_BUFFER_LIST pBufLists)
+{
+ for (PNET_BUFFER_LIST pList = pBufLists; pList; pList = NET_BUFFER_LIST_NEXT_NBL(pList))
+ {
+ for (PNET_BUFFER pBuf = NET_BUFFER_LIST_FIRST_NB(pList); pBuf; pBuf = NET_BUFFER_NEXT_NB(pBuf))
+ {
+ Log6(("%s packet: cb=%d offset=%d", pszMsg, NET_BUFFER_DATA_LENGTH(pBuf), NET_BUFFER_DATA_OFFSET(pBuf)));
+ for (PMDL pMdl = NET_BUFFER_FIRST_MDL(pBuf);
+ pMdl != NULL;
+ pMdl = NDIS_MDL_LINKAGE(pMdl))
+ {
+ Log6((" MDL: cb=%d", MmGetMdlByteCount(pMdl)));
+ }
+ Log6(("\n"));
+ }
+ }
+}
+
+DECLINLINE(const char *) vboxNetAdpWinEthTypeStr(uint16_t uType)
+{
+ switch (uType)
+ {
+ case RTNET_ETHERTYPE_IPV4: return "IP";
+ case RTNET_ETHERTYPE_IPV6: return "IPv6";
+ case RTNET_ETHERTYPE_ARP: return "ARP";
+ }
+ return "unknown";
+}
+
+#define VBOXNETADP_PKTDMPSIZE 0x50
+
+/**
+ * Dump a packet to debug log.
+ *
+ * @param cpPacket The packet.
+ * @param cb The size of the packet.
+ * @param cszText A string denoting direction of packet transfer.
+ */
+DECLINLINE(void) vboxNetAdpWinDumpPacket(PCINTNETSG pSG, const char *cszText)
+{
+ uint8_t bPacket[VBOXNETADP_PKTDMPSIZE];
+
+ uint32_t cb = pSG->cbTotal < VBOXNETADP_PKTDMPSIZE ? pSG->cbTotal : VBOXNETADP_PKTDMPSIZE;
+ IntNetSgReadEx(pSG, 0, cb, bPacket);
+
+ AssertReturnVoid(cb >= 14);
+
+ uint8_t *pHdr = bPacket;
+ uint8_t *pEnd = bPacket + cb;
+ AssertReturnVoid(pEnd - pHdr >= 14);
+ uint16_t uEthType = RT_N2H_U16(*(uint16_t*)(pHdr+12));
+ Log2(("NetADP: %s (%d bytes), %RTmac => %RTmac, EthType=%s(0x%x)\n",
+ cszText, pSG->cbTotal, pHdr+6, pHdr, vboxNetAdpWinEthTypeStr(uEthType), uEthType));
+ pHdr += sizeof(RTNETETHERHDR);
+ if (uEthType == RTNET_ETHERTYPE_VLAN)
+ {
+ AssertReturnVoid(pEnd - pHdr >= 4);
+ uEthType = RT_N2H_U16(*(uint16_t*)(pHdr+2));
+ Log2((" + VLAN: id=%d EthType=%s(0x%x)\n", RT_N2H_U16(*(uint16_t*)(pHdr)) & 0xFFF,
+ vboxNetAdpWinEthTypeStr(uEthType), uEthType));
+ pHdr += 2 * sizeof(uint16_t);
+ }
+ uint8_t uProto = 0xFF;
+ switch (uEthType)
+ {
+ case RTNET_ETHERTYPE_IPV6:
+ AssertReturnVoid(pEnd - pHdr >= 40);
+ uProto = pHdr[6];
+ Log2((" + IPv6: %RTnaipv6 => %RTnaipv6\n", pHdr+8, pHdr+24));
+ pHdr += 40;
+ break;
+ case RTNET_ETHERTYPE_IPV4:
+ AssertReturnVoid(pEnd - pHdr >= 20);
+ uProto = pHdr[9];
+ Log2((" + IP: %RTnaipv4 => %RTnaipv4\n", *(uint32_t*)(pHdr+12), *(uint32_t*)(pHdr+16)));
+ pHdr += (pHdr[0] & 0xF) * 4;
+ break;
+ case RTNET_ETHERTYPE_ARP:
+ AssertReturnVoid(pEnd - pHdr >= 28);
+ AssertReturnVoid(RT_N2H_U16(*(uint16_t*)(pHdr+2)) == RTNET_ETHERTYPE_IPV4);
+ switch (RT_N2H_U16(*(uint16_t*)(pHdr+6)))
+ {
+ case 1: /* ARP request */
+ Log2((" + ARP-REQ: who-has %RTnaipv4 tell %RTnaipv4\n",
+ *(uint32_t*)(pHdr+24), *(uint32_t*)(pHdr+14)));
+ break;
+ case 2: /* ARP reply */
+ Log2((" + ARP-RPL: %RTnaipv4 is-at %RTmac\n",
+ *(uint32_t*)(pHdr+14), pHdr+8));
+ break;
+ default:
+ Log2((" + ARP: unknown op %d\n", RT_N2H_U16(*(uint16_t*)(pHdr+6))));
+ break;
+ }
+ break;
+ /* There is no default case as uProto is initialized with 0xFF */
+ }
+ while (uProto != 0xFF)
+ {
+ switch (uProto)
+ {
+ case 0: /* IPv6 Hop-by-Hop option*/
+ case 60: /* IPv6 Destination option*/
+ case 43: /* IPv6 Routing option */
+ case 44: /* IPv6 Fragment option */
+ Log2((" + IPv6 option (%d): <not implemented>\n", uProto));
+ uProto = pHdr[0];
+ pHdr += pHdr[1] * 8 + 8; /* Skip to the next extension/protocol */
+ break;
+ case 51: /* IPv6 IPsec AH */
+ Log2((" + IPv6 IPsec AH: <not implemented>\n"));
+ uProto = pHdr[0];
+ pHdr += (pHdr[1] + 2) * 4; /* Skip to the next extension/protocol */
+ break;
+ case 50: /* IPv6 IPsec ESP */
+ /* Cannot decode IPsec, fall through */
+ Log2((" + IPv6 IPsec ESP: <not implemented>\n"));
+ uProto = 0xFF;
+ break;
+ case 59: /* No Next Header */
+ Log2((" + IPv6 No Next Header\n"));
+ uProto = 0xFF;
+ break;
+ case 58: /* IPv6-ICMP */
+ switch (pHdr[0])
+ {
+ case 1: Log2((" + IPv6-ICMP: destination unreachable, code %d\n", pHdr[1])); break;
+ case 128: Log2((" + IPv6-ICMP: echo request\n")); break;
+ case 129: Log2((" + IPv6-ICMP: echo reply\n")); break;
+ default: Log2((" + IPv6-ICMP: unknown type %d, code %d\n", pHdr[0], pHdr[1])); break;
+ }
+ uProto = 0xFF;
+ break;
+ case 1: /* ICMP */
+ switch (pHdr[0])
+ {
+ case 0: Log2((" + ICMP: echo reply\n")); break;
+ case 8: Log2((" + ICMP: echo request\n")); break;
+ case 3: Log2((" + ICMP: destination unreachable, code %d\n", pHdr[1])); break;
+ default: Log2((" + ICMP: unknown type %d, code %d\n", pHdr[0], pHdr[1])); break;
+ }
+ uProto = 0xFF;
+ break;
+ case 6: /* TCP */
+ Log2((" + TCP: src=%d dst=%d seq=%x ack=%x\n",
+ RT_N2H_U16(*(uint16_t*)(pHdr)), RT_N2H_U16(*(uint16_t*)(pHdr+2)),
+ RT_N2H_U32(*(uint32_t*)(pHdr+4)), RT_N2H_U32(*(uint32_t*)(pHdr+8))));
+ uProto = 0xFF;
+ break;
+ case 17: /* UDP */
+ Log2((" + UDP: src=%d dst=%d\n",
+ RT_N2H_U16(*(uint16_t*)(pHdr)), RT_N2H_U16(*(uint16_t*)(pHdr+2))));
+ uProto = 0xFF;
+ break;
+ default:
+ Log2((" + Unknown: proto=0x%x\n", uProto));
+ uProto = 0xFF;
+ break;
+ }
+ }
+ Log3(("%.*Rhxd\n", cb, bPacket));
+}
+
+#else /* !DEBUG */
+//# define vboxNetAdpWinDumpFilterTypes(uFlags) do { } while (0)
+//# define vboxNetAdpWinDumpOffloadSettings(p) do { } while (0)
+//# define vboxNetAdpWinDumpSetOffloadSettings(p) do { } while (0)
+# define vboxNetAdpWinDumpPackets(m,l) do { } while (0)
+# define vboxNetAdpWinDumpPacket(p,t) do { } while (0)
+#endif /* !DEBUG */
+
+
+DECLHIDDEN(VBOXNETADPWIN_PACKET_TYPE) vboxNetAdpWinPacketType(PINTNETSG pSG)
+{
+ static const uint8_t g_abBcastAddr[] = { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+ AssertReturn(pSG->cbTotal >= sizeof(g_abBcastAddr), kVBoxNetAdpWinPacketType_Unicast);
+ AssertReturn(pSG->cSegsUsed > 0, kVBoxNetAdpWinPacketType_Unicast);
+ AssertReturn(pSG->aSegs[0].cb >= sizeof(g_abBcastAddr), kVBoxNetAdpWinPacketType_Unicast);
+ if (!memcmp(pSG->aSegs[0].pv, g_abBcastAddr, sizeof(g_abBcastAddr)))
+ return kVBoxNetAdpWinPacketType_Broadcast;
+ if ((*(uint8_t*)pSG->aSegs[0].pv) & 1)
+ return kVBoxNetAdpWinPacketType_Multicast;
+ return kVBoxNetAdpWinPacketType_Unicast;
+}
+
+DECLINLINE(void) vboxNetAdpWinUpdateStats(uint64_t *pPacketStats, uint64_t *pOctetStats, PINTNETSG pSG)
+{
+ VBOXNETADPWIN_PACKET_TYPE enmPktType = vboxNetAdpWinPacketType(pSG);
+ ASMAtomicIncU64(&pPacketStats[enmPktType]);
+ ASMAtomicAddU64(&pOctetStats[enmPktType], pSG->cbTotal);
+}
+
+DECLINLINE(void) vboxNetAdpWinFreeMdlChain(PMDL pMdl)
+{
+ PMDL pMdlNext;
+ while (pMdl)
+ {
+ pMdlNext = pMdl->Next;
+ PUCHAR pDataBuf;
+ ULONG cb = 0;
+ NdisQueryMdl(pMdl, &pDataBuf, &cb, NormalPagePriority);
+ NdisFreeMdl(pMdl);
+ Log4(("vboxNetAdpWinFreeMdlChain: freed MDL 0x%p\n", pMdl));
+ NdisFreeMemory(pDataBuf, 0, 0);
+ Log4(("vboxNetAdpWinFreeMdlChain: freed data buffer 0x%p\n", pDataBuf));
+ pMdl = pMdlNext;
+ }
+}
+
+DECLHIDDEN(PNET_BUFFER_LIST) vboxNetAdpWinSGtoNB(PVBOXNETADP_ADAPTER pThis, PINTNETSG pSG)
+{
+ AssertReturn(pSG->cSegsUsed >= 1, NULL);
+ LogFlow(("==>vboxNetAdpWinSGtoNB: segments=%d hPool=%p cb=%u\n", pSG->cSegsUsed,
+ pThis->hPool, pSG->cbTotal));
+ AssertReturn(pThis->hPool, NULL);
+
+
+ PNET_BUFFER_LIST pBufList = NULL;
+ ULONG cbMdl = pSG->cbTotal;
+ ULONG uDataOffset = cbMdl - pSG->cbTotal;
+ PUCHAR pDataBuf = (PUCHAR)NdisAllocateMemoryWithTagPriority(pThis->hAdapter, cbMdl,
+ VBOXNETADP_MEM_TAG, NormalPoolPriority);
+ if (pDataBuf)
+ {
+ Log4(("vboxNetAdpWinSGtoNB: allocated data buffer (cb=%u) 0x%p\n", cbMdl, pDataBuf));
+ PMDL pMdl = NdisAllocateMdl(pThis->hAdapter, pDataBuf, cbMdl);
+ if (!pMdl)
+ {
+ NdisFreeMemory(pDataBuf, 0, 0);
+ Log4(("vboxNetAdpWinSGtoNB: freed data buffer 0x%p\n", pDataBuf));
+ LogError(("vboxNetAdpWinSGtoNB: failed to allocate an MDL (cb=%u)\n", cbMdl));
+ LogFlow(("<==vboxNetAdpWinSGtoNB: return NULL\n"));
+ return NULL;
+ }
+ PUCHAR pDst = pDataBuf + uDataOffset;
+ for (int i = 0; i < pSG->cSegsUsed; i++)
+ {
+ NdisMoveMemory(pDst, pSG->aSegs[i].pv, pSG->aSegs[i].cb);
+ pDst += pSG->aSegs[i].cb;
+ }
+ pBufList = NdisAllocateNetBufferAndNetBufferList(pThis->hPool,
+ 0 /* ContextSize */,
+ 0 /* ContextBackFill */,
+ pMdl,
+ uDataOffset,
+ pSG->cbTotal);
+ if (pBufList)
+ {
+ Log4(("vboxNetAdpWinSGtoNB: allocated NBL+NB 0x%p\n", pBufList));
+ pBufList->SourceHandle = pThis->hAdapter;
+ /** @todo Do we need to initialize anything else? */
+ }
+ else
+ {
+ LogError(("vboxNetAdpWinSGtoNB: failed to allocate an NBL+NB\n"));
+ vboxNetAdpWinFreeMdlChain(pMdl);
+ }
+ }
+ else
+ {
+ LogError(("vboxNetAdpWinSGtoNB: failed to allocate data buffer (size=%u)\n", cbMdl));
+ }
+
+ LogFlow(("<==vboxNetAdpWinSGtoNB: return %p\n", pBufList));
+ return pBufList;
+}
+
+DECLINLINE(void) vboxNetAdpWinDestroySG(PINTNETSG pSG)
+{
+ NdisFreeMemory(pSG, 0, 0);
+ Log4(("vboxNetAdpWinDestroySG: freed SG 0x%p\n", pSG));
+}
+
+/**
+ * Worker for vboxNetAdpWinNBtoSG() that gets the max segment count needed.
+ * @note vboxNetAdpWinNBtoSG may use fewer depending on cbPacket and offset!
+ * @note vboxNetLwfWinCalcSegments() is a copy of this code.
+ */
+DECLINLINE(ULONG) vboxNetAdpWinCalcSegments(PNET_BUFFER pNetBuf)
+{
+ ULONG cSegs = 0;
+ for (PMDL pMdl = NET_BUFFER_CURRENT_MDL(pNetBuf); pMdl; pMdl = NDIS_MDL_LINKAGE(pMdl))
+ {
+ /* Skip empty MDLs (see @bugref{9233}) */
+ if (MmGetMdlByteCount(pMdl))
+ cSegs++;
+ }
+ return cSegs;
+}
+
+/**
+ * @note vboxNetLwfWinNBtoSG() is a copy of this code.
+ */
+DECLHIDDEN(PINTNETSG) vboxNetAdpWinNBtoSG(PVBOXNETADP_ADAPTER pThis, PNET_BUFFER pNetBuf)
+{
+ ULONG cbPacket = NET_BUFFER_DATA_LENGTH(pNetBuf);
+ ULONG cSegs = vboxNetAdpWinCalcSegments(pNetBuf);
+ /* Allocate and initialize SG */
+ PINTNETSG pSG = (PINTNETSG)NdisAllocateMemoryWithTagPriority(pThis->hAdapter,
+ RT_UOFFSETOF_DYN(INTNETSG, aSegs[cSegs]),
+ VBOXNETADP_MEM_TAG,
+ NormalPoolPriority);
+ AssertReturn(pSG, pSG);
+ Log4(("vboxNetAdpWinNBtoSG: allocated SG 0x%p\n", pSG));
+ IntNetSgInitTempSegs(pSG, cbPacket /*cbTotal*/, cSegs, cSegs /*cSegsUsed*/);
+
+ ULONG uOffset = NET_BUFFER_CURRENT_MDL_OFFSET(pNetBuf);
+ cSegs = 0;
+ for (PMDL pMdl = NET_BUFFER_CURRENT_MDL(pNetBuf);
+ pMdl != NULL && cbPacket > 0;
+ pMdl = NDIS_MDL_LINKAGE(pMdl))
+ {
+ ULONG cbSrc = MmGetMdlByteCount(pMdl);
+ if (cbSrc == 0)
+ continue; /* Skip empty MDLs (see @bugref{9233}) */
+
+ PUCHAR pSrc = (PUCHAR)MmGetSystemAddressForMdlSafe(pMdl, LowPagePriority);
+ if (!pSrc)
+ {
+ vboxNetAdpWinDestroySG(pSG);
+ return NULL;
+ }
+
+ /* Handle the offset in the current (which is the first for us) MDL */
+ if (uOffset)
+ {
+ if (uOffset < cbSrc)
+ {
+ pSrc += uOffset;
+ cbSrc -= uOffset;
+ uOffset = 0;
+ }
+ else
+ {
+ /* This is an invalid MDL chain */
+ vboxNetAdpWinDestroySG(pSG);
+ return NULL;
+ }
+ }
+
+ /* Do not read the last MDL beyond packet's end */
+ if (cbSrc > cbPacket)
+ cbSrc = cbPacket;
+
+ Assert(cSegs < pSG->cSegsAlloc);
+ pSG->aSegs[cSegs].pv = pSrc;
+ pSG->aSegs[cSegs].cb = cbSrc;
+ pSG->aSegs[cSegs].Phys = NIL_RTHCPHYS;
+ cSegs++;
+ cbPacket -= cbSrc;
+ }
+
+ Assert(cbPacket == 0);
+ Assert(cSegs <= pSG->cSegsUsed);
+
+ /* Update actual segment count in case we used fewer than anticipated. */
+ pSG->cSegsUsed = (uint16_t)cSegs;
+
+ return pSG;
+}
+
+DECLINLINE(bool) vboxNetAdpWinIsActive(PVBOXNETADP_ADAPTER pThis)
+{
+ if (vboxNetAdpWinGetState(pThis) != kVBoxNetAdpWinState_Running)
+ return false;
+ if (pThis->enmTrunkState != INTNETTRUNKIFSTATE_ACTIVE)
+ return false;
+ AssertPtrReturn(pThis->pSwitchPort, false);
+ return true;
+}
+
+DECLHIDDEN(bool) vboxNetAdpWinForwardToIntNet(PVBOXNETADP_ADAPTER pThis, PNET_BUFFER_LIST pList, uint32_t fSrc)
+{
+ if (!vboxNetAdpWinIsActive(pThis))
+ {
+ LogFlow(("vboxNetAdpWinForwardToIntNet: not active\n"));
+ return false;
+ }
+ AssertReturn(pThis->pSwitchPort, false);
+ AssertReturn(pThis->pSwitchPort->pfnRecv, false);
+ LogFlow(("==>vboxNetAdpWinForwardToIntNet\n"));
+
+ if (ASMAtomicIncS32(&pThis->cBusy) == 1)
+ NdisResetEvent(&pThis->EventIdle);
+ for (PNET_BUFFER pBuf = NET_BUFFER_LIST_FIRST_NB(pList); pBuf; pBuf = NET_BUFFER_NEXT_NB(pBuf))
+ {
+ PINTNETSG pSG = vboxNetAdpWinNBtoSG(pThis, pBuf);
+ if (pSG)
+ {
+ vboxNetAdpWinUpdateStats(pThis->au64StatsOutPackets, pThis->au64StatsOutOctets, pSG);
+ vboxNetAdpWinDumpPacket(pSG, (fSrc & INTNETTRUNKDIR_WIRE)?"intnet <-- wire":"intnet <-- host");
+ pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, NULL, pSG, fSrc);
+ vboxNetAdpWinDestroySG(pSG);
+ }
+ }
+ if (ASMAtomicDecS32(&pThis->cBusy) == 0)
+ NdisSetEvent(&pThis->EventIdle);
+
+ return true;
+}
+
+
+/**
+ * @copydoc INTNETTRUNKIFPORT::pfnRetain
+ */
+static DECLCALLBACK(void) vboxNetAdpWinPortRetain(PINTNETTRUNKIFPORT pIfPort)
+{
+ PVBOXNETADP_ADAPTER pThis = IFPORT_2_VBOXNETADP_ADAPTER(pIfPort);
+ RT_NOREF1(pThis);
+ LogFlow(("vboxNetAdpWinPortRetain: pThis=%p, pIfPort=%p\n", pThis, pIfPort));
+}
+
+/**
+ * @copydoc INTNETTRUNKIFPORT::pfnRelease
+ */
+static DECLCALLBACK(void) vboxNetAdpWinPortRelease(PINTNETTRUNKIFPORT pIfPort)
+{
+ PVBOXNETADP_ADAPTER pThis = IFPORT_2_VBOXNETADP_ADAPTER(pIfPort);
+ RT_NOREF1(pThis);
+ LogFlow(("vboxNetAdpWinPortRelease: pThis=%p, pIfPort=%p\n", pThis, pIfPort));
+}
+
+/**
+ * @copydoc INTNETTRUNKIFPORT::pfnDisconnectAndRelease
+ */
+static DECLCALLBACK(void) vboxNetAdpWinPortDisconnectAndRelease(PINTNETTRUNKIFPORT pIfPort)
+{
+ PVBOXNETADP_ADAPTER pThis = IFPORT_2_VBOXNETADP_ADAPTER(pIfPort);
+
+ LogFlow(("vboxNetAdpWinPortDisconnectAndRelease: pThis=%p, pIfPort=%p\n", pThis, pIfPort));
+ /*
+ * Serious paranoia.
+ */
+ AssertPtr(pThis);
+ Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
+ Assert(pThis->MyPort.u32VersionEnd == INTNETTRUNKIFPORT_VERSION);
+ AssertPtr(pThis->pGlobals);
+ Assert(pThis->szName[0]);
+
+ AssertPtr(pThis->pSwitchPort);
+ Assert(pThis->enmTrunkState == INTNETTRUNKIFSTATE_DISCONNECTING);
+
+ pThis->pSwitchPort = NULL;
+}
+
+/**
+ * @copydoc INTNETTRUNKIFPORT::pfnSetState
+ */
+static DECLCALLBACK(INTNETTRUNKIFSTATE) vboxNetAdpWinPortSetState(PINTNETTRUNKIFPORT pIfPort, INTNETTRUNKIFSTATE enmState)
+{
+ PVBOXNETADP_ADAPTER pThis = IFPORT_2_VBOXNETADP_ADAPTER(pIfPort);
+ INTNETTRUNKIFSTATE enmOldTrunkState;
+
+ LogFlow(("vboxNetAdpWinPortSetState: pThis=%p, pIfPort=%p, enmState=%d\n", pThis, pIfPort, enmState));
+ /*
+ * Input validation.
+ */
+ AssertPtr(pThis);
+ AssertPtr(pThis->pGlobals);
+ Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
+ AssertPtrReturn(pThis->pSwitchPort, INTNETTRUNKIFSTATE_INVALID);
+ AssertReturn(enmState > INTNETTRUNKIFSTATE_INVALID && enmState < INTNETTRUNKIFSTATE_END,
+ INTNETTRUNKIFSTATE_INVALID);
+
+ enmOldTrunkState = pThis->enmTrunkState;
+ if (enmOldTrunkState != enmState)
+ ASMAtomicWriteU32((uint32_t volatile *)&pThis->enmTrunkState, enmState);
+
+ return enmOldTrunkState;
+}
+
+/**
+ * @copydoc INTNETTRUNKIFPORT::pfnWaitForIdle
+ */
+static DECLCALLBACK(int) vboxNetAdpWinPortWaitForIdle(PINTNETTRUNKIFPORT pIfPort, uint32_t cMillies)
+{
+ PVBOXNETADP_ADAPTER pThis = IFPORT_2_VBOXNETADP_ADAPTER(pIfPort);
+ int rc;
+
+ LogFlow(("vboxNetAdpWinPortWaitForIdle: pThis=%p, pIfPort=%p, cMillies=%u\n", pThis, pIfPort, cMillies));
+ /*
+ * Input validation.
+ */
+ AssertPtr(pThis);
+ Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
+ AssertPtrReturn(pThis->pSwitchPort, VERR_INVALID_STATE);
+ AssertReturn(pThis->enmTrunkState == INTNETTRUNKIFSTATE_DISCONNECTING, VERR_INVALID_STATE);
+
+ rc = NdisWaitEvent(&pThis->EventIdle, cMillies) ? VINF_SUCCESS : VERR_TIMEOUT;
+
+ return rc;
+}
+
+/**
+ * @copydoc INTNETTRUNKIFPORT::pfnXmit
+ */
+static DECLCALLBACK(int) vboxNetAdpWinPortXmit(PINTNETTRUNKIFPORT pIfPort, void *pvIfData, PINTNETSG pSG, uint32_t fDst)
+{
+ RT_NOREF1(fDst);
+ PVBOXNETADP_ADAPTER pThis = IFPORT_2_VBOXNETADP_ADAPTER(pIfPort);
+ int rc = VINF_SUCCESS;
+
+ LogFlow(("vboxNetAdpWinPortXmit: pThis=%p, pIfPort=%p, pvIfData=%p, pSG=%p, fDst=0x%x\n", pThis, pIfPort, pvIfData, pSG, fDst));
+ RT_NOREF1(pvIfData);
+ /*
+ * Input validation.
+ */
+ AssertPtr(pThis);
+ AssertPtr(pSG);
+ Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
+ AssertPtrReturn(pThis->pSwitchPort, VERR_INVALID_STATE);
+
+ vboxNetAdpWinDumpPacket(pSG, "intnet --> host");
+
+ /*
+ * First of all, indicate we are busy. It is possible the trunk or the adapter
+ * will get paused or even disconnected, so we need to check the state after
+ * we have marked ourselves busy.
+ * Later, when NDIS returns all buffers, we will mark ourselves idle.
+ */
+ if (ASMAtomicIncS32(&pThis->cBusy) == 1)
+ NdisResetEvent(&pThis->EventIdle);
+
+ if (vboxNetAdpWinIsActive(pThis))
+ {
+ PNET_BUFFER_LIST pBufList = vboxNetAdpWinSGtoNB(pThis, pSG);
+ if (pBufList)
+ {
+ NdisMIndicateReceiveNetBufferLists(pThis->hAdapter, pBufList, NDIS_DEFAULT_PORT_NUMBER, 1, 0);
+ vboxNetAdpWinUpdateStats(pThis->au64StatsInPackets, pThis->au64StatsInOctets, pSG);
+ }
+ }
+
+ return rc;
+}
+
+/**
+ * @copydoc INTNETTRUNKIFPORT::pfnNotifyMacAddress
+ */
+static DECLCALLBACK(void) vboxNetAdpWinPortNotifyMacAddress(PINTNETTRUNKIFPORT pIfPort, void *pvIfData, PCRTMAC pMac)
+{
+ PVBOXNETADP_ADAPTER pThis = IFPORT_2_VBOXNETADP_ADAPTER(pIfPort);
+
+ LogFlow(("vboxNetAdpWinPortNotifyMacAddress: pThis=%p, pIfPort=%p, pvIfData=%p, pMac=%p\n", pThis, pIfPort, pvIfData, pMac));
+ RT_NOREF3(pThis, pvIfData, pMac);
+ /*
+ * Input validation.
+ */
+ AssertPtr(pThis);
+ Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
+
+ /// @todo Do we really need to handle this?
+}
+
+
+/**
+ * @copydoc INTNETTRUNKIFPORT::pfnConnectInterface
+ */
+static DECLCALLBACK(int) vboxNetAdpWinPortConnectInterface(PINTNETTRUNKIFPORT pIfPort, void *pvIf, void **ppvIfData)
+{
+ PVBOXNETADP_ADAPTER pThis = IFPORT_2_VBOXNETADP_ADAPTER(pIfPort);
+ int rc;
+
+ LogFlow(("vboxNetAdpWinPortConnectInterface: pThis=%p, pIfPort=%p, pvIf=%p, ppvIfData=%p\n", pThis, pIfPort, pvIf, ppvIfData));
+ RT_NOREF3(pThis, pvIf, ppvIfData);
+ /*
+ * Input validation.
+ */
+ AssertPtr(pThis);
+ Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
+
+ rc = VINF_SUCCESS;
+
+ return rc;
+}
+
+
+/**
+ * @copydoc INTNETTRUNKIFPORT::pfnDisconnectInterface
+ */
+static DECLCALLBACK(void) vboxNetAdpWinPortDisconnectInterface(PINTNETTRUNKIFPORT pIfPort, void *pvIfData)
+{
+ PVBOXNETADP_ADAPTER pThis = IFPORT_2_VBOXNETADP_ADAPTER(pIfPort);
+ int rc;
+
+ LogFlow(("vboxNetAdpWinPortDisconnectInterface: pThis=%p, pIfPort=%p, pvIfData=%p\n", pThis, pIfPort, pvIfData));
+ RT_NOREF2(pThis, pvIfData);
+ /*
+ * Input validation.
+ */
+ AssertPtr(pThis);
+ Assert(pThis->MyPort.u32Version == INTNETTRUNKIFPORT_VERSION);
+
+ rc = VINF_SUCCESS;
+ AssertRC(rc);
+}
+
+
+
+/**
+ * Implements the SUPDRV component factor interface query method.
+ *
+ * @returns Pointer to an interface. NULL if not supported.
+ *
+ * @param pSupDrvFactory Pointer to the component factory registration structure.
+ * @param pSession The session - unused.
+ * @param pszInterfaceUuid The factory interface id.
+ */
+static DECLCALLBACK(void *) vboxNetAdpWinQueryFactoryInterface(PCSUPDRVFACTORY pSupDrvFactory, PSUPDRVSESSION pSession,
+ const char *pszInterfaceUuid)
+{
+ PVBOXNETADPGLOBALS pGlobals = (PVBOXNETADPGLOBALS)((uint8_t *)pSupDrvFactory - RT_UOFFSETOF(VBOXNETADPGLOBALS, SupDrvFactory));
+
+ /*
+ * Convert the UUID strings and compare them.
+ */
+ RTUUID UuidReq;
+ int rc = RTUuidFromStr(&UuidReq, pszInterfaceUuid);
+ if (RT_SUCCESS(rc))
+ {
+ if (!RTUuidCompareStr(&UuidReq, INTNETTRUNKFACTORY_UUID_STR))
+ {
+ NdisAcquireSpinLock(&pGlobals->Lock);
+ if (pGlobals->enmIdcState == kVBoxNetAdpWinIdcState_Connected)
+ {
+ pGlobals->cFactoryRefs++;
+ NdisResetEvent(&pGlobals->EventUnloadAllowed);
+ }
+ NdisReleaseSpinLock(&pGlobals->Lock);
+ return &pGlobals->TrunkFactory;
+ }
+#ifdef LOG_ENABLED
+ else
+ Log(("VBoxNetFlt: unknown factory interface query (%s)\n", pszInterfaceUuid));
+#endif
+ }
+ else
+ Log(("VBoxNetFlt: rc=%Rrc, uuid=%s\n", rc, pszInterfaceUuid));
+
+ RT_NOREF1(pSession);
+ return NULL;
+}
+
+
+DECLHIDDEN(void) vboxNetAdpWinReportCapabilities(PVBOXNETADP_ADAPTER pThis)
+{
+ if (pThis->pSwitchPort)
+ {
+ pThis->pSwitchPort->pfnReportMacAddress(pThis->pSwitchPort, &pThis->MacAddr);
+ /* Promiscuous mode makes no sense for host-only adapters, does it? */
+ pThis->pSwitchPort->pfnReportGsoCapabilities(pThis->pSwitchPort, 0,
+ INTNETTRUNKDIR_WIRE | INTNETTRUNKDIR_HOST);
+ pThis->pSwitchPort->pfnReportNoPreemptDsts(pThis->pSwitchPort, 0 /* none */);
+ }
+}
+
+/**
+ * @copydoc INTNETTRUNKFACTORY::pfnCreateAndConnect
+ */
+static DECLCALLBACK(int) vboxNetAdpWinFactoryCreateAndConnect(PINTNETTRUNKFACTORY pIfFactory, const char *pszName,
+ PINTNETTRUNKSWPORT pSwitchPort, uint32_t fFlags,
+ PINTNETTRUNKIFPORT *ppIfPort)
+{
+ PVBOXNETADPGLOBALS pGlobals = (PVBOXNETADPGLOBALS)((uint8_t *)pIfFactory - RT_UOFFSETOF(VBOXNETADPGLOBALS, TrunkFactory));
+
+ LogFlow(("==>vboxNetAdpWinFactoryCreateAndConnect: pszName=%p:{%s} fFlags=%#x\n", pszName, pszName, fFlags));
+ Assert(pGlobals->cFactoryRefs > 0);
+ AssertMsgReturn(!(fFlags & ~(INTNETTRUNKFACTORY_FLAG_NO_PROMISC)),
+ ("%#x\n", fFlags), VERR_INVALID_PARAMETER);
+
+ DbgPrint("vboxNetAdpWinFactoryCreateAndConnect: looking for %s...\n", pszName);
+ PVBOXNETADP_ADAPTER pAdapter = NULL;
+ NdisAcquireSpinLock(&pGlobals->Lock);
+ RTListForEach(&g_VBoxNetAdpGlobals.ListOfAdapters, pAdapter, VBOXNETADP_ADAPTER, node)
+ {
+ Log(("vboxNetAdpWinFactoryCreateAndConnect: evaluating adapter=%s\n", pAdapter->szName));
+ DbgPrint("vboxNetAdpWinFactoryCreateAndConnect: evaluating %s...\n", pAdapter->szName);
+ if (!RTStrICmp(pszName, pAdapter->szName))
+ {
+ pAdapter->pSwitchPort = pSwitchPort;
+ *ppIfPort = &pAdapter->MyPort;
+ NdisReleaseSpinLock(&g_VBoxNetAdpGlobals.Lock); /// @todo too early? adp should have been connected by the time we do this
+ Log(("vboxNetAdpWinFactoryCreateAndConnect: found matching adapter, name=%s\n", pszName));
+ vboxNetAdpWinReportCapabilities(pAdapter);
+ /// @todo I guess there is no need in vboxNetAdpWinRegisterIpAddrNotifier(pThis);
+ LogFlow(("<==vboxNetAdpWinFactoryCreateAndConnect: return VINF_SUCCESS\n"));
+ return VINF_SUCCESS;
+ }
+ }
+ NdisReleaseSpinLock(&pGlobals->Lock);
+ /// @todo vboxNetAdpLogErrorEvent(IO_ERR_INTERNAL_ERROR, STATUS_SUCCESS, 6);
+ DbgPrint("vboxNetAdpWinFactoryCreateAndConnect: could not find %s\n", pszName);
+ LogFlow(("<==vboxNetAdpWinFactoryCreateAndConnect: return VERR_INTNET_FLT_IF_NOT_FOUND\n"));
+ return VERR_INTNET_FLT_IF_NOT_FOUND;
+}
+
+
+/**
+ * @copydoc INTNETTRUNKFACTORY::pfnRelease
+ */
+static DECLCALLBACK(void) vboxNetAdpWinFactoryRelease(PINTNETTRUNKFACTORY pIfFactory)
+{
+ PVBOXNETADPGLOBALS pGlobals = (PVBOXNETADPGLOBALS)((uint8_t *)pIfFactory - RT_OFFSETOF(VBOXNETADPGLOBALS, TrunkFactory));
+
+ NdisAcquireSpinLock(&pGlobals->Lock);
+ int32_t cRefs = ASMAtomicDecS32(&pGlobals->cFactoryRefs);
+ if (cRefs == 0)
+ NdisSetEvent(&pGlobals->EventUnloadAllowed);
+ NdisReleaseSpinLock(&pGlobals->Lock);
+ Assert(cRefs >= 0); NOREF(cRefs);
+ LogFlow(("vboxNetAdpWinFactoryRelease: cRefs=%d (new)\n", cRefs));
+}
+
+
+
+/* IDC */
+
+DECLINLINE(const char *) vboxNetAdpWinIdcStateToText(uint32_t enmState)
+{
+ switch (enmState)
+ {
+ case kVBoxNetAdpWinIdcState_Disconnected: return "Disconnected";
+ case kVBoxNetAdpWinIdcState_Connecting: return "Connecting";
+ case kVBoxNetAdpWinIdcState_Connected: return "Connected";
+ case kVBoxNetAdpWinIdcState_Stopping: return "Stopping";
+ }
+ return "Unknown";
+}
+
+static VOID vboxNetAdpWinInitIdcWorker(PVOID pvContext)
+{
+ int rc;
+ PVBOXNETADPGLOBALS pGlobals = (PVBOXNETADPGLOBALS)pvContext;
+
+ /*
+ * Note that we break the rules here and access IDC state wihout acquiring
+ * the lock. This is ok because vboxNetAdpWinUnload will wait for this
+ * thread to terminate itself and we always use atomic access to IDC state.
+ * We check the state (while holding the lock) further when we have succeeded
+ * to connect. We cannot take the lock here and release it later as we will
+ * be holding it for too long.
+ */
+ while (ASMAtomicReadU32(&pGlobals->enmIdcState) == kVBoxNetAdpWinIdcState_Connecting)
+ {
+ /*
+ * Establish a connection to SUPDRV and register our component factory.
+ */
+ rc = SUPR0IdcOpen(&pGlobals->SupDrvIDC, 0 /* iReqVersion = default */, 0 /* iMinVersion = default */, NULL, NULL, NULL);
+ if (RT_SUCCESS(rc))
+ {
+ rc = SUPR0IdcComponentRegisterFactory(&pGlobals->SupDrvIDC, &pGlobals->SupDrvFactory);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * At this point we should take the lock to access IDC state as
+ * we technically may now race with factory methods.
+ */
+ NdisAcquireSpinLock(&pGlobals->Lock);
+ bool fSuccess = ASMAtomicCmpXchgU32(&pGlobals->enmIdcState,
+ kVBoxNetAdpWinIdcState_Connected,
+ kVBoxNetAdpWinIdcState_Connecting);
+ NdisReleaseSpinLock(&pGlobals->Lock);
+ if (!fSuccess)
+ {
+ /* The state has been changed (the only valid transition is to "Stopping"), undo init */
+ rc = SUPR0IdcComponentDeregisterFactory(&pGlobals->SupDrvIDC, &pGlobals->SupDrvFactory);
+ AssertRC(rc);
+ SUPR0IdcClose(&pGlobals->SupDrvIDC);
+ Log(("vboxNetAdpWinInitIdcWorker: state change (Connecting -> %s) while initializing IDC, closed IDC, rc=0x%x\n",
+ vboxNetAdpWinIdcStateToText(ASMAtomicReadU32(&pGlobals->enmIdcState)), rc));
+ }
+ else
+ {
+ Log(("vboxNetAdpWinInitIdcWorker: IDC state change Connecting -> Connected\n"));
+ }
+ }
+ }
+ else
+ {
+ LARGE_INTEGER WaitIn100nsUnits;
+ WaitIn100nsUnits.QuadPart = -(LONGLONG)5000000; /* 0.5 sec */
+ KeDelayExecutionThread(KernelMode, FALSE /* non-alertable */, &WaitIn100nsUnits);
+ }
+ }
+ PsTerminateSystemThread(STATUS_SUCCESS);
+}
+
+
+DECLHIDDEN(int) vboxNetAdpWinStartInitIdcThread(PVBOXNETADPGLOBALS pGlobals)
+{
+ int rc = VERR_INVALID_STATE;
+
+ /* No locking needed yet */
+ if (ASMAtomicCmpXchgU32(&pGlobals->enmIdcState, kVBoxNetAdpWinIdcState_Connecting, kVBoxNetAdpWinIdcState_Disconnected))
+ {
+ Log(("vboxNetAdpWinStartInitIdcThread: IDC state change Diconnected -> Connecting\n"));
+
+ NTSTATUS Status = PsCreateSystemThread(&g_VBoxNetAdpGlobals.hInitIdcThread,
+ THREAD_ALL_ACCESS,
+ NULL,
+ NULL,
+ NULL,
+ vboxNetAdpWinInitIdcWorker,
+ &g_VBoxNetAdpGlobals);
+ Log(("vboxNetAdpWinStartInitIdcThread: create IDC initialization thread, status=0x%x\n", Status));
+ if (Status != STATUS_SUCCESS)
+ {
+ LogError(("vboxNetAdpWinStartInitIdcThread: IDC initialization failed (system thread creation, status=0x%x)\n", Status));
+ /*
+ * We failed to init IDC and there will be no second chance.
+ */
+ Log(("vboxNetAdpWinStartInitIdcThread: IDC state change Connecting -> Diconnected\n"));
+ ASMAtomicWriteU32(&g_VBoxNetAdpGlobals.enmIdcState, kVBoxNetAdpWinIdcState_Disconnected);
+ }
+ rc = RTErrConvertFromNtStatus(Status);
+ }
+ return rc;
+}
+
+
+
+/* === !!!! */
+
+
+NDIS_OID g_SupportedOids[] =
+{
+ OID_GEN_CURRENT_LOOKAHEAD,
+ OID_GEN_CURRENT_PACKET_FILTER,
+ OID_GEN_INTERRUPT_MODERATION,
+ OID_GEN_LINK_PARAMETERS,
+ OID_GEN_MAXIMUM_TOTAL_SIZE,
+ OID_GEN_RCV_OK,
+ OID_GEN_RECEIVE_BLOCK_SIZE,
+ OID_GEN_RECEIVE_BUFFER_SPACE,
+ OID_GEN_STATISTICS,
+ OID_GEN_TRANSMIT_BLOCK_SIZE,
+ OID_GEN_TRANSMIT_BUFFER_SPACE,
+ OID_GEN_VENDOR_DESCRIPTION,
+ OID_GEN_VENDOR_DRIVER_VERSION,
+ OID_GEN_VENDOR_ID,
+ OID_GEN_XMIT_OK,
+ OID_802_3_PERMANENT_ADDRESS,
+ OID_802_3_CURRENT_ADDRESS,
+ OID_802_3_MULTICAST_LIST,
+ OID_802_3_MAXIMUM_LIST_SIZE,
+ OID_PNP_CAPABILITIES,
+ OID_PNP_QUERY_POWER,
+ OID_PNP_SET_POWER
+};
+
+DECLHIDDEN(NDIS_STATUS) vboxNetAdpWinAllocAdapter(NDIS_HANDLE hAdapter, PVBOXNETADP_ADAPTER *ppAdapter, ULONG uIfIndex)
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PVBOXNETADP_ADAPTER pAdapter = NULL;
+ PVBOXNETADPGLOBALS pGlobals = &g_VBoxNetAdpGlobals;
+
+ LogFlow(("==>vboxNetAdpWinAllocAdapter: adapter handle=%p\n", hAdapter));
+
+ /* Get the name */
+ UNICODE_STRING strUnicodeName;
+ Status = NdisMQueryAdapterInstanceName(&strUnicodeName, hAdapter);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ LogError(("vboxNetAdpWinAllocAdapter: NdisMQueryAdapterInstanceName failed with 0x%x\n", Status));
+ return Status;
+ }
+
+ ANSI_STRING strAnsiName;
+ /* We use the miniport name to associate this filter module with the netflt instance */
+ NTSTATUS rc = RtlUnicodeStringToAnsiString(&strAnsiName,
+ &strUnicodeName,
+ TRUE);
+ if (rc != STATUS_SUCCESS)
+ {
+ LogError(("vboxNetAdpWinAllocAdapter: RtlUnicodeStringToAnsiString(%ls) failed with 0x%x\n",
+ strUnicodeName, rc));
+ //vboxNetAdpLogErrorEvent(IO_ERR_INTERNAL_ERROR, NDIS_STATUS_FAILURE, 2);
+ NdisFreeMemory(strUnicodeName.Buffer, 0, 0);
+ return NDIS_STATUS_FAILURE;
+ }
+ NdisFreeMemory(strUnicodeName.Buffer, 0, 0);
+ DbgPrint("vboxNetAdpWinAllocAdapter: name=%Z\n", &strAnsiName);
+
+ *ppAdapter = NULL;
+
+ UINT cbAdapterWithNameExtra = sizeof(VBOXNETADP_ADAPTER) + strAnsiName.Length;
+ pAdapter = (PVBOXNETADP_ADAPTER)NdisAllocateMemoryWithTagPriority(pGlobals->hMiniportDriver,
+ cbAdapterWithNameExtra,
+ VBOXNETADPWIN_TAG,
+ NormalPoolPriority);
+ if (!pAdapter)
+ {
+ RtlFreeAnsiString(&strAnsiName);
+ Status = NDIS_STATUS_RESOURCES;
+ Log(("vboxNetAdpWinAllocAdapter: Out of memory while allocating adapter context (size=%d)\n", sizeof(VBOXNETADP_ADAPTER)));
+ }
+ else
+ {
+ NdisZeroMemory(pAdapter, cbAdapterWithNameExtra);
+ NdisMoveMemory(pAdapter->szName, strAnsiName.Buffer, strAnsiName.Length);
+ RtlFreeAnsiString(&strAnsiName);
+
+ /* Allocate buffer pool */
+ NET_BUFFER_LIST_POOL_PARAMETERS PoolParams;
+ NdisZeroMemory(&PoolParams, sizeof(PoolParams));
+ PoolParams.Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
+ PoolParams.Header.Revision = NET_BUFFER_LIST_POOL_PARAMETERS_REVISION_1;
+ PoolParams.Header.Size = sizeof(PoolParams);
+ PoolParams.ProtocolId = NDIS_PROTOCOL_ID_DEFAULT;
+ PoolParams.fAllocateNetBuffer = TRUE;
+ PoolParams.ContextSize = 0;
+ PoolParams.PoolTag = VBOXNETADP_MEM_TAG;
+ pAdapter->hPool = NdisAllocateNetBufferListPool(hAdapter, &PoolParams);
+ if (!pAdapter->hPool)
+ {
+ LogError(("vboxNetAdpWinAllocAdapter: NdisAllocateNetBufferListPool failed\n"));
+ NdisFreeMemory(pAdapter, 0, 0);
+ return NDIS_STATUS_RESOURCES;
+ }
+ Log4(("vboxNetAdpWinAllocAdapter: allocated NBL+NB pool 0x%p\n", pAdapter->hPool));
+
+ pAdapter->hAdapter = hAdapter;
+ pAdapter->MyPort.u32Version = INTNETTRUNKIFPORT_VERSION;
+ pAdapter->MyPort.pfnRetain = vboxNetAdpWinPortRetain;
+ pAdapter->MyPort.pfnRelease = vboxNetAdpWinPortRelease;
+ pAdapter->MyPort.pfnDisconnectAndRelease = vboxNetAdpWinPortDisconnectAndRelease;
+ pAdapter->MyPort.pfnSetState = vboxNetAdpWinPortSetState;
+ pAdapter->MyPort.pfnWaitForIdle = vboxNetAdpWinPortWaitForIdle;
+ pAdapter->MyPort.pfnXmit = vboxNetAdpWinPortXmit;
+ pAdapter->MyPort.pfnNotifyMacAddress = vboxNetAdpWinPortNotifyMacAddress;
+ pAdapter->MyPort.pfnConnectInterface = vboxNetAdpWinPortConnectInterface;
+ pAdapter->MyPort.pfnDisconnectInterface = vboxNetAdpWinPortDisconnectInterface;
+ pAdapter->MyPort.u32VersionEnd = INTNETTRUNKIFPORT_VERSION;
+ pAdapter->pGlobals = pGlobals;
+ pAdapter->enmAdapterState = kVBoxNetAdpWinState_Initializing;
+ pAdapter->enmTrunkState = INTNETTRUNKIFSTATE_INACTIVE;
+ pAdapter->cBusy = 0;
+ NdisInitializeEvent(&pAdapter->EventIdle);
+ NdisSetEvent(&pAdapter->EventIdle); /* We are idle initially */
+
+ /* Use a locally administered version of the OUI we use for the guest NICs. */
+ pAdapter->MacAddr.au8[0] = 0x08 | 2;
+ pAdapter->MacAddr.au8[1] = 0x00;
+ pAdapter->MacAddr.au8[2] = 0x27;
+
+ pAdapter->MacAddr.au8[3] = (uIfIndex >> 16) & 0xFF;
+ pAdapter->MacAddr.au8[4] = (uIfIndex >> 8) & 0xFF;
+ pAdapter->MacAddr.au8[5] = uIfIndex & 0xFF;
+
+ NdisAcquireSpinLock(&pGlobals->Lock);
+ RTListPrepend(&pGlobals->ListOfAdapters, &pAdapter->node);
+ NdisReleaseSpinLock(&pGlobals->Lock);
+
+ *ppAdapter = pAdapter;
+ }
+ LogFlow(("<==vboxNetAdpWinAllocAdapter: status=0x%x\n", Status));
+ return Status;
+}
+
+DECLHIDDEN(void) vboxNetAdpWinFreeAdapter(PVBOXNETADP_ADAPTER pAdapter)
+{
+ /* Remove from adapter chain */
+ NdisAcquireSpinLock(&pAdapter->pGlobals->Lock);
+ RTListNodeRemove(&pAdapter->node);
+ NdisReleaseSpinLock(&pAdapter->pGlobals->Lock);
+
+ NdisFreeMemory(pAdapter, 0, 0);
+}
+
+DECLINLINE(NDIS_MEDIA_CONNECT_STATE) vboxNetAdpWinGetConnectState(PVBOXNETADP_ADAPTER pAdapter)
+{
+ RT_NOREF1(pAdapter);
+ return MediaConnectStateConnected;
+}
+
+
+DECLHIDDEN(NDIS_STATUS) vboxNetAdpWinInitializeEx(IN NDIS_HANDLE NdisMiniportHandle,
+ IN NDIS_HANDLE MiniportDriverContext,
+ IN PNDIS_MINIPORT_INIT_PARAMETERS MiniportInitParameters)
+{
+ RT_NOREF1(MiniportDriverContext);
+ PVBOXNETADP_ADAPTER pAdapter = NULL;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+
+ LogFlow(("==>vboxNetAdpWinInitializeEx: miniport=0x%x\n", NdisMiniportHandle));
+
+ do
+ {
+ NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES RAttrs = {{0}};
+ NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES GAttrs = {{0}};
+
+ Status = vboxNetAdpWinAllocAdapter(NdisMiniportHandle, &pAdapter, MiniportInitParameters->IfIndex);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ Log(("vboxNetAdpWinInitializeEx: Failed to allocate the adapter context with 0x%x\n", Status));
+ break;
+ }
+
+ RAttrs.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES;
+ RAttrs.Header.Size = NDIS_SIZEOF_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_1;
+ RAttrs.Header.Revision = NDIS_MINIPORT_ADAPTER_REGISTRATION_ATTRIBUTES_REVISION_1;
+ RAttrs.MiniportAdapterContext = pAdapter;
+ RAttrs.AttributeFlags = VBOXNETADPWIN_ATTR_FLAGS; // NDIS_MINIPORT_ATTRIBUTES_NDIS_WDM
+ RAttrs.CheckForHangTimeInSeconds = VBOXNETADPWIN_HANG_CHECK_TIME;
+ RAttrs.InterfaceType = NdisInterfaceInternal;
+
+ Status = NdisMSetMiniportAttributes(NdisMiniportHandle,
+ (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&RAttrs);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ Log(("vboxNetAdpWinInitializeEx: NdisMSetMiniportAttributes(registration) failed with 0x%x\n", Status));
+ break;
+ }
+
+ /// @todo Registry?
+
+ /// @todo WDM stack?
+
+ /// @todo DPC?
+
+ GAttrs.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES;
+ GAttrs.Header.Size = NDIS_SIZEOF_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_1;
+ GAttrs.Header.Revision = NDIS_MINIPORT_ADAPTER_GENERAL_ATTRIBUTES_REVISION_1;
+
+ GAttrs.MediaType = NdisMedium802_3;
+ GAttrs.PhysicalMediumType = NdisPhysicalMediumUnspecified;
+ GAttrs.MtuSize = 1500; /// @todo
+ GAttrs.MaxXmitLinkSpeed = VBOXNETADPWIN_LINK_SPEED;
+ GAttrs.XmitLinkSpeed = VBOXNETADPWIN_LINK_SPEED;
+ GAttrs.MaxRcvLinkSpeed = VBOXNETADPWIN_LINK_SPEED;
+ GAttrs.RcvLinkSpeed = VBOXNETADPWIN_LINK_SPEED;
+ GAttrs.MediaConnectState = vboxNetAdpWinGetConnectState(pAdapter);
+ GAttrs.MediaDuplexState = MediaDuplexStateFull;
+ GAttrs.LookaheadSize = 1500; /// @todo
+ GAttrs.MacOptions = VBOXNETADP_MAC_OPTIONS;
+ GAttrs.SupportedPacketFilters = VBOXNETADP_SUPPORTED_FILTERS;
+ GAttrs.MaxMulticastListSize = 32; /// @todo
+
+ GAttrs.MacAddressLength = ETH_LENGTH_OF_ADDRESS;
+ Assert(GAttrs.MacAddressLength == sizeof(pAdapter->MacAddr));
+ memcpy(GAttrs.PermanentMacAddress, pAdapter->MacAddr.au8, GAttrs.MacAddressLength);
+ memcpy(GAttrs.CurrentMacAddress, pAdapter->MacAddr.au8, GAttrs.MacAddressLength);
+
+ GAttrs.RecvScaleCapabilities = NULL;
+ GAttrs.AccessType = NET_IF_ACCESS_BROADCAST;
+ GAttrs.DirectionType = NET_IF_DIRECTION_SENDRECEIVE;
+ GAttrs.ConnectionType = NET_IF_CONNECTION_DEDICATED;
+ GAttrs.IfType = IF_TYPE_ETHERNET_CSMACD;
+ GAttrs.IfConnectorPresent = false;
+ GAttrs.SupportedStatistics = VBOXNETADPWIN_SUPPORTED_STATISTICS;
+ GAttrs.SupportedPauseFunctions = NdisPauseFunctionsUnsupported;
+ GAttrs.DataBackFillSize = 0;
+ GAttrs.ContextBackFillSize = 0;
+ GAttrs.SupportedOidList = g_SupportedOids;
+ GAttrs.SupportedOidListLength = sizeof(g_SupportedOids);
+ GAttrs.AutoNegotiationFlags = NDIS_LINK_STATE_DUPLEX_AUTO_NEGOTIATED;
+ GAttrs.PowerManagementCapabilities = &g_VBoxNetAdpGlobals.PMCaps;
+
+ Status = NdisMSetMiniportAttributes(NdisMiniportHandle,
+ (PNDIS_MINIPORT_ADAPTER_ATTRIBUTES)&GAttrs);
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ Log(("vboxNetAdpWinInitializeEx: NdisMSetMiniportAttributes(general) failed with 0x%x\n", Status));
+ break;
+ }
+
+ VBOXNETADPWIN_ADAPTER_STATE enmPrevState = vboxNetAdpWinSetState(pAdapter, kVBoxNetAdpWinState_Paused);
+ RT_NOREF1(enmPrevState);
+ Assert(enmPrevState == kVBoxNetAdpWinState_Initializing);
+ } while (false);
+
+ if (Status != NDIS_STATUS_SUCCESS)
+ {
+ if (pAdapter)
+ vboxNetAdpWinFreeAdapter(pAdapter);
+ }
+
+ LogFlow(("<==vboxNetAdpWinInitializeEx: status=0x%x\n", Status));
+ return Status;
+}
+
+DECLHIDDEN(VOID) vboxNetAdpWinHaltEx(IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_HALT_ACTION HaltAction)
+{
+ RT_NOREF1(HaltAction);
+ PVBOXNETADP_ADAPTER pThis = (PVBOXNETADP_ADAPTER)MiniportAdapterContext;
+ LogFlow(("==>vboxNetAdpWinHaltEx\n"));
+ AssertPtr(pThis);
+ Assert(vboxNetAdpWinGetState(pThis) == kVBoxNetAdpWinState_Paused);
+ /*
+ * Check if the trunk is active which means the adapter gets disabled
+ * while it is used by VM(s) and we need to disconnect the trunk.
+ */
+ if (pThis->pSwitchPort && pThis->enmTrunkState == INTNETTRUNKIFSTATE_ACTIVE)
+ pThis->pSwitchPort->pfnDisconnect(pThis->pSwitchPort, &pThis->MyPort, NULL);
+ /*
+ * Since we are already in the paused state and we have disconnected
+ * the trunk, we can safely destroy this adapter.
+ */
+ vboxNetAdpWinFreeAdapter(pThis);
+ LogFlow(("<==vboxNetAdpWinHaltEx\n"));
+}
+
+DECLHIDDEN(NDIS_STATUS) vboxNetAdpWinPause(IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNDIS_MINIPORT_PAUSE_PARAMETERS MiniportPauseParameters)
+{
+ RT_NOREF1(MiniportPauseParameters);
+ PVBOXNETADP_ADAPTER pThis = (PVBOXNETADP_ADAPTER)MiniportAdapterContext;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ LogFlow(("==>vboxNetAdpWinPause\n"));
+ VBOXNETADPWIN_ADAPTER_STATE enmPrevState = vboxNetAdpWinSetState(pThis, kVBoxNetAdpWinState_Pausing);
+ Assert(enmPrevState == kVBoxNetAdpWinState_Running);
+ if (!NdisWaitEvent(&pThis->EventIdle, 1000 /* ms */))
+ {
+ LogError(("vboxNetAdpWinPause: timed out while pausing the adapter\n"));
+ /// @todo implement NDIS_STATUS_PENDING case? probably not.
+ }
+ enmPrevState = vboxNetAdpWinSetState(pThis, kVBoxNetAdpWinState_Paused);
+ Assert(enmPrevState == kVBoxNetAdpWinState_Pausing);
+ LogFlow(("<==vboxNetAdpWinPause: status=0x%x\n", Status));
+ return Status;
+}
+
+DECLHIDDEN(NDIS_STATUS) vboxNetAdpWinRestart(IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNDIS_MINIPORT_RESTART_PARAMETERS MiniportRestartParameters)
+{
+ RT_NOREF1(MiniportRestartParameters);
+ PVBOXNETADP_ADAPTER pThis = (PVBOXNETADP_ADAPTER)MiniportAdapterContext;
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ LogFlow(("==>vboxNetAdpWinRestart\n"));
+ VBOXNETADPWIN_ADAPTER_STATE enmPrevState = vboxNetAdpWinSetState(pThis, kVBoxNetAdpWinState_Restarting);
+ Assert(enmPrevState == kVBoxNetAdpWinState_Paused);
+ /// @todo anything?
+ enmPrevState = vboxNetAdpWinSetState(pThis, kVBoxNetAdpWinState_Running);
+ Assert(enmPrevState == kVBoxNetAdpWinState_Restarting);
+ LogFlow(("<==vboxNetAdpWinRestart: status=0x%x\n", Status));
+ return Status;
+}
+
+DECLINLINE(uint64_t) vboxNetAdpWinStatsTotals(uint64_t *pStats)
+{
+ return pStats[kVBoxNetAdpWinPacketType_Unicast]
+ + pStats[kVBoxNetAdpWinPacketType_Multicast]
+ + pStats[kVBoxNetAdpWinPacketType_Broadcast];
+}
+
+DECLINLINE(PVOID) vboxNetAdpWinStatsU64(uint64_t *pTmp, ULONG *pcbTmp, uint64_t u64Stat)
+{
+ *pcbTmp = sizeof(*pTmp);
+ *pTmp = u64Stat;
+ return pTmp;
+}
+
+DECLHIDDEN(NDIS_STATUS) vboxNetAdpWinOidRqQuery(PVBOXNETADP_ADAPTER pThis,
+ PNDIS_OID_REQUEST pRequest)
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ struct _NDIS_OID_REQUEST::_REQUEST_DATA::_QUERY *pQuery = &pRequest->DATA.QUERY_INFORMATION;
+
+ LogFlow(("==>vboxNetAdpWinOidRqQuery\n"));
+
+ uint64_t u64Tmp = 0;
+ ULONG ulTmp = 0;
+ PVOID pInfo = &ulTmp;
+ ULONG cbInfo = sizeof(ulTmp);
+
+ switch (pQuery->Oid)
+ {
+ case OID_GEN_INTERRUPT_MODERATION:
+ {
+ PNDIS_INTERRUPT_MODERATION_PARAMETERS pParams =
+ (PNDIS_INTERRUPT_MODERATION_PARAMETERS)pQuery->InformationBuffer;
+ cbInfo = NDIS_SIZEOF_INTERRUPT_MODERATION_PARAMETERS_REVISION_1;
+ if (cbInfo > pQuery->InformationBufferLength)
+ break;
+ pParams->Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
+ pParams->Header.Revision = NDIS_INTERRUPT_MODERATION_PARAMETERS_REVISION_1;
+ pParams->Header.Size = NDIS_SIZEOF_INTERRUPT_MODERATION_PARAMETERS_REVISION_1;
+ pParams->Flags = 0;
+ pParams->InterruptModeration = NdisInterruptModerationNotSupported;
+ pInfo = NULL; /* Do not copy */
+ break;
+ }
+ case OID_GEN_MAXIMUM_TOTAL_SIZE:
+ case OID_GEN_RECEIVE_BLOCK_SIZE:
+ case OID_GEN_TRANSMIT_BLOCK_SIZE:
+ ulTmp = VBOXNETADP_MAX_FRAME_SIZE;
+ break;
+ case OID_GEN_RECEIVE_BUFFER_SPACE:
+ case OID_GEN_TRANSMIT_BUFFER_SPACE:
+ /// @todo Make configurable
+ ulTmp = VBOXNETADP_MAX_FRAME_SIZE * 40;
+ break;
+ case OID_GEN_RCV_OK:
+ pInfo = vboxNetAdpWinStatsU64(&u64Tmp, &cbInfo, vboxNetAdpWinStatsTotals(pThis->au64StatsInPackets));
+ break;
+ case OID_GEN_XMIT_OK:
+ pInfo = vboxNetAdpWinStatsU64(&u64Tmp, &cbInfo, vboxNetAdpWinStatsTotals(pThis->au64StatsOutPackets));
+ break;
+ case OID_GEN_STATISTICS:
+ {
+ PNDIS_STATISTICS_INFO pStats =
+ (PNDIS_STATISTICS_INFO)pQuery->InformationBuffer;
+ cbInfo = NDIS_SIZEOF_STATISTICS_INFO_REVISION_1;
+ if (cbInfo > pQuery->InformationBufferLength)
+ break;
+ pInfo = NULL; /* Do not copy */
+ memset(pStats, 0, cbInfo);
+ pStats->Header.Type = NDIS_OBJECT_TYPE_DEFAULT;
+ pStats->Header.Revision = NDIS_STATISTICS_INFO_REVISION_1;
+ pStats->Header.Size = NDIS_SIZEOF_STATISTICS_INFO_REVISION_1;
+ pStats->SupportedStatistics =
+ NDIS_STATISTICS_FLAGS_VALID_DIRECTED_FRAMES_RCV
+ | NDIS_STATISTICS_FLAGS_VALID_MULTICAST_FRAMES_RCV
+ | NDIS_STATISTICS_FLAGS_VALID_BROADCAST_FRAMES_RCV
+ | NDIS_STATISTICS_FLAGS_VALID_BYTES_RCV
+ | NDIS_STATISTICS_FLAGS_VALID_RCV_DISCARDS
+ | NDIS_STATISTICS_FLAGS_VALID_RCV_ERROR
+ | NDIS_STATISTICS_FLAGS_VALID_DIRECTED_FRAMES_XMIT
+ | NDIS_STATISTICS_FLAGS_VALID_MULTICAST_FRAMES_XMIT
+ | NDIS_STATISTICS_FLAGS_VALID_BROADCAST_FRAMES_XMIT
+ | NDIS_STATISTICS_FLAGS_VALID_BYTES_XMIT
+ | NDIS_STATISTICS_FLAGS_VALID_XMIT_ERROR
+ | NDIS_STATISTICS_FLAGS_VALID_XMIT_DISCARDS
+ | NDIS_STATISTICS_FLAGS_VALID_DIRECTED_BYTES_RCV
+ | NDIS_STATISTICS_FLAGS_VALID_MULTICAST_BYTES_RCV
+ | NDIS_STATISTICS_FLAGS_VALID_BROADCAST_BYTES_RCV
+ | NDIS_STATISTICS_FLAGS_VALID_DIRECTED_BYTES_XMIT
+ | NDIS_STATISTICS_FLAGS_VALID_MULTICAST_BYTES_XMIT
+ | NDIS_STATISTICS_FLAGS_VALID_BROADCAST_BYTES_XMIT;
+
+ pStats->ifHCInOctets = vboxNetAdpWinStatsTotals(pThis->au64StatsInOctets);
+ pStats->ifHCInUcastPkts = ASMAtomicReadU64(&pThis->au64StatsInPackets[kVBoxNetAdpWinPacketType_Unicast]);
+ pStats->ifHCInMulticastPkts = ASMAtomicReadU64(&pThis->au64StatsInPackets[kVBoxNetAdpWinPacketType_Multicast]);
+ pStats->ifHCInBroadcastPkts = ASMAtomicReadU64(&pThis->au64StatsInPackets[kVBoxNetAdpWinPacketType_Broadcast]);
+ pStats->ifHCOutOctets = vboxNetAdpWinStatsTotals(pThis->au64StatsOutOctets);;
+ pStats->ifHCOutUcastPkts = ASMAtomicReadU64(&pThis->au64StatsOutPackets[kVBoxNetAdpWinPacketType_Unicast]);
+ pStats->ifHCOutMulticastPkts = ASMAtomicReadU64(&pThis->au64StatsOutPackets[kVBoxNetAdpWinPacketType_Multicast]);
+ pStats->ifHCOutBroadcastPkts = ASMAtomicReadU64(&pThis->au64StatsOutPackets[kVBoxNetAdpWinPacketType_Broadcast]);
+ pStats->ifHCInUcastOctets = ASMAtomicReadU64(&pThis->au64StatsInOctets[kVBoxNetAdpWinPacketType_Unicast]);
+ pStats->ifHCInMulticastOctets = ASMAtomicReadU64(&pThis->au64StatsInOctets[kVBoxNetAdpWinPacketType_Multicast]);
+ pStats->ifHCInBroadcastOctets = ASMAtomicReadU64(&pThis->au64StatsInOctets[kVBoxNetAdpWinPacketType_Broadcast]);
+ pStats->ifHCOutUcastOctets = ASMAtomicReadU64(&pThis->au64StatsOutOctets[kVBoxNetAdpWinPacketType_Unicast]);
+ pStats->ifHCOutMulticastOctets = ASMAtomicReadU64(&pThis->au64StatsOutOctets[kVBoxNetAdpWinPacketType_Multicast]);
+ pStats->ifHCOutBroadcastOctets = ASMAtomicReadU64(&pThis->au64StatsOutOctets[kVBoxNetAdpWinPacketType_Broadcast]);
+ break;
+ }
+ case OID_GEN_VENDOR_DESCRIPTION:
+ pInfo = VBOXNETADP_VENDOR_NAME;
+ cbInfo = sizeof(VBOXNETADP_VENDOR_NAME);
+ break;
+ case OID_GEN_VENDOR_DRIVER_VERSION:
+ ulTmp = (VBOXNETADP_VERSION_NDIS_MAJOR << 16) | VBOXNETADP_VERSION_NDIS_MINOR;
+ break;
+ case OID_GEN_VENDOR_ID:
+ ulTmp = VBOXNETADP_VENDOR_ID;
+ break;
+ case OID_802_3_PERMANENT_ADDRESS:
+ case OID_802_3_CURRENT_ADDRESS:
+ pInfo = &pThis->MacAddr;
+ cbInfo = sizeof(pThis->MacAddr);
+ break;
+ //case OID_802_3_MULTICAST_LIST:
+ case OID_802_3_MAXIMUM_LIST_SIZE:
+ ulTmp = VBOXNETADP_MCAST_LIST_SIZE;
+ break;
+ case OID_PNP_CAPABILITIES:
+ pInfo = &pThis->pGlobals->PMCaps;
+ cbInfo = sizeof(pThis->pGlobals->PMCaps);
+ break;
+ case OID_PNP_QUERY_POWER:
+ pInfo = NULL; /* Do not copy */
+ cbInfo = 0;
+ break;
+ default:
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ if (cbInfo > pQuery->InformationBufferLength)
+ {
+ pQuery->BytesNeeded = cbInfo;
+ Status = NDIS_STATUS_BUFFER_TOO_SHORT;
+ }
+ else
+ {
+ if (pInfo)
+ NdisMoveMemory(pQuery->InformationBuffer, pInfo, cbInfo);
+ pQuery->BytesWritten = cbInfo;
+ }
+ }
+
+ LogFlow(("<==vboxNetAdpWinOidRqQuery: status=0x%x\n", Status));
+ return Status;
+}
+
+DECLHIDDEN(NDIS_STATUS) vboxNetAdpWinOidRqSet(PVBOXNETADP_ADAPTER pAdapter,
+ PNDIS_OID_REQUEST pRequest)
+{
+ RT_NOREF1(pAdapter);
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ struct _NDIS_OID_REQUEST::_REQUEST_DATA::_SET *pSet = &pRequest->DATA.SET_INFORMATION;
+
+ LogFlow(("==>vboxNetAdpWinOidRqSet\n"));
+
+ switch (pSet->Oid)
+ {
+ case OID_GEN_CURRENT_LOOKAHEAD:
+ if (pSet->InformationBufferLength != sizeof(ULONG))
+ {
+ pSet->BytesNeeded = sizeof(ULONG);
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ break;
+ }
+ /// @todo For the time being we simply ignore lookahead settings.
+ pSet->BytesRead = sizeof(ULONG);
+ Status = NDIS_STATUS_SUCCESS;
+ break;
+
+ case OID_GEN_CURRENT_PACKET_FILTER:
+ if (pSet->InformationBufferLength != sizeof(ULONG))
+ {
+ pSet->BytesNeeded = sizeof(ULONG);
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ break;
+ }
+ /// @todo For the time being we simply ignore packet filter settings.
+ pSet->BytesRead = pSet->InformationBufferLength;
+ Status = NDIS_STATUS_SUCCESS;
+ break;
+
+ case OID_GEN_INTERRUPT_MODERATION:
+ pSet->BytesNeeded = 0;
+ pSet->BytesRead = 0;
+ Status = NDIS_STATUS_INVALID_DATA;
+ break;
+
+ case OID_PNP_SET_POWER:
+ if (pSet->InformationBufferLength < sizeof(NDIS_DEVICE_POWER_STATE))
+ {
+ Status = NDIS_STATUS_INVALID_LENGTH;
+ break;
+ }
+ pSet->BytesRead = sizeof(NDIS_DEVICE_POWER_STATE);
+ Status = NDIS_STATUS_SUCCESS;
+ break;
+
+ default:
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ LogFlow(("<==vboxNetAdpWinOidRqSet: status=0x%x\n", Status));
+ return Status;
+}
+
+DECLHIDDEN(NDIS_STATUS) vboxNetAdpWinOidRequest(IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNDIS_OID_REQUEST NdisRequest)
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ PVBOXNETADP_ADAPTER pAdapter = (PVBOXNETADP_ADAPTER)MiniportAdapterContext;
+ LogFlow(("==>vboxNetAdpWinOidRequest\n"));
+ vboxNetCmnWinDumpOidRequest(__FUNCTION__, NdisRequest);
+
+ switch (NdisRequest->RequestType)
+ {
+#if 0
+ case NdisRequestMethod:
+ Status = vboxNetAdpWinOidRqMethod(pAdapter, NdisRequest);
+ break;
+#endif
+
+ case NdisRequestSetInformation:
+ Status = vboxNetAdpWinOidRqSet(pAdapter, NdisRequest);
+ break;
+
+ case NdisRequestQueryInformation:
+ case NdisRequestQueryStatistics:
+ Status = vboxNetAdpWinOidRqQuery(pAdapter, NdisRequest);
+ break;
+
+ default:
+ Status = NDIS_STATUS_NOT_SUPPORTED;
+ break;
+ }
+ LogFlow(("<==vboxNetAdpWinOidRequest: status=0x%x\n", Status));
+ return Status;
+}
+
+DECLHIDDEN(VOID) vboxNetAdpWinSendNetBufferLists(IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNET_BUFFER_LIST NetBufferLists,
+ IN NDIS_PORT_NUMBER PortNumber,
+ IN ULONG SendFlags)
+{
+ RT_NOREF1(PortNumber);
+ PVBOXNETADP_ADAPTER pAdapter = (PVBOXNETADP_ADAPTER)MiniportAdapterContext;
+ LogFlow(("==>vboxNetAdpWinSendNetBufferLists\n"));
+ PNET_BUFFER_LIST pNbl = NetBufferLists;
+ vboxNetAdpWinDumpPackets("vboxNetAdpWinSendNetBufferLists: got", pNbl);
+
+ /* We alwast complete all send requests. */
+ for (pNbl = NetBufferLists; pNbl; pNbl = NET_BUFFER_LIST_NEXT_NBL(pNbl))
+ {
+ vboxNetAdpWinForwardToIntNet(pAdapter, pNbl, INTNETTRUNKDIR_HOST);
+ NET_BUFFER_LIST_STATUS(pNbl) = NDIS_STATUS_SUCCESS;
+ }
+ NdisMSendNetBufferListsComplete(pAdapter->hAdapter, NetBufferLists,
+ (SendFlags & NDIS_SEND_FLAGS_DISPATCH_LEVEL) ?
+ NDIS_SEND_COMPLETE_FLAGS_DISPATCH_LEVEL : 0);
+ LogFlow(("<==vboxNetAdpWinSendNetBufferLists\n"));
+}
+
+DECLHIDDEN(VOID) vboxNetAdpWinReturnNetBufferLists(IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNET_BUFFER_LIST NetBufferLists,
+ IN ULONG ReturnFlags)
+{
+ LogFlow(("==>vboxNetAdpWinReturnNetBufferLists\n"));
+ RT_NOREF1(ReturnFlags);
+ PVBOXNETADP_ADAPTER pThis = (PVBOXNETADP_ADAPTER)MiniportAdapterContext;
+ PNET_BUFFER_LIST pList = NetBufferLists;
+ while (pList)
+ {
+ Assert(pList->SourceHandle == pThis->hAdapter);
+ Assert(NET_BUFFER_LIST_FIRST_NB(pList));
+ Assert(NET_BUFFER_FIRST_MDL(NET_BUFFER_LIST_FIRST_NB(pList)));
+
+ PNET_BUFFER_LIST pNextList = NET_BUFFER_LIST_NEXT_NBL(pList);
+
+ vboxNetAdpWinFreeMdlChain(NET_BUFFER_FIRST_MDL(NET_BUFFER_LIST_FIRST_NB(pList)));
+ NdisFreeNetBufferList(pList);
+ Log4(("vboxNetLwfWinReturnNetBufferLists: freed NBL+NB+MDL+Data 0x%p\n", pList));
+ Assert(ASMAtomicReadS32(&pThis->cBusy) > 0);
+ if (ASMAtomicDecS32(&pThis->cBusy) == 0)
+ NdisSetEvent(&pThis->EventIdle);
+
+ pList = pNextList;
+ }
+ LogFlow(("<==vboxNetAdpWinReturnNetBufferLists\n"));
+}
+
+DECLHIDDEN(VOID) vboxNetAdpWinCancelSend(IN NDIS_HANDLE MiniportAdapterContext,
+ IN PVOID CancelId)
+{
+ RT_NOREF2(MiniportAdapterContext, CancelId);
+ LogFlow(("==>vboxNetAdpWinCancelSend\n"));
+ Log(("vboxNetAdpWinCancelSend: We should not be here!\n"));
+ LogFlow(("<==vboxNetAdpWinCancelSend\n"));
+}
+
+
+DECLHIDDEN(BOOLEAN) vboxNetAdpWinCheckForHangEx(IN NDIS_HANDLE MiniportAdapterContext)
+{
+ RT_NOREF1(MiniportAdapterContext);
+ LogFlow(("==>vboxNetAdpWinCheckForHangEx\n"));
+ LogFlow(("<==vboxNetAdpWinCheckForHangEx return false\n"));
+ return FALSE;
+}
+
+DECLHIDDEN(NDIS_STATUS) vboxNetAdpWinResetEx(IN NDIS_HANDLE MiniportAdapterContext,
+ OUT PBOOLEAN AddressingReset)
+{
+ RT_NOREF2(MiniportAdapterContext, AddressingReset);
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ LogFlow(("==>vboxNetAdpWinResetEx\n"));
+ LogFlow(("<==vboxNetAdpWinResetEx: status=0x%x\n", Status));
+ return Status;
+}
+
+DECLHIDDEN(VOID) vboxNetAdpWinDevicePnPEventNotify(IN NDIS_HANDLE MiniportAdapterContext,
+ IN PNET_DEVICE_PNP_EVENT NetDevicePnPEvent)
+{
+ RT_NOREF2(MiniportAdapterContext, NetDevicePnPEvent);
+ LogFlow(("==>vboxNetAdpWinDevicePnPEventNotify\n"));
+ Log(("vboxNetAdpWinDevicePnPEventNotify: PnP event=%d\n", NetDevicePnPEvent->DevicePnPEvent));
+ LogFlow(("<==vboxNetAdpWinDevicePnPEventNotify\n"));
+}
+
+
+DECLHIDDEN(VOID) vboxNetAdpWinShutdownEx(IN NDIS_HANDLE MiniportAdapterContext,
+ IN NDIS_SHUTDOWN_ACTION ShutdownAction)
+{
+ RT_NOREF2(MiniportAdapterContext, ShutdownAction);
+ LogFlow(("==>vboxNetAdpWinShutdownEx\n"));
+ Log(("vboxNetAdpWinShutdownEx: action=%d\n", ShutdownAction));
+ LogFlow(("<==vboxNetAdpWinShutdownEx\n"));
+}
+
+DECLHIDDEN(VOID) vboxNetAdpWinCancelOidRequest(IN NDIS_HANDLE MiniportAdapterContext,
+ IN PVOID RequestId)
+{
+ RT_NOREF2(MiniportAdapterContext, RequestId);
+ LogFlow(("==>vboxNetAdpWinCancelOidRequest\n"));
+ Log(("vboxNetAdpWinCancelOidRequest: req id=%p\n", RequestId));
+ LogFlow(("<==vboxNetAdpWinCancelOidRequest\n"));
+}
+
+
+
+DECLHIDDEN(VOID) vboxNetAdpWinUnload(IN PDRIVER_OBJECT DriverObject)
+{
+ RT_NOREF1(DriverObject);
+ LogFlow(("==>vboxNetAdpWinUnload\n"));
+ PVBOXNETADPGLOBALS pGlobals = &g_VBoxNetAdpGlobals;
+ int rc;
+ NDIS_STATUS Status;
+ PKTHREAD pThread = NULL;
+
+ /* We are about to disconnect IDC, let's make it clear so the factories will know */
+ NdisAcquireSpinLock(&pGlobals->Lock);
+ uint32_t enmPrevState = ASMAtomicXchgU32(&g_VBoxNetAdpGlobals.enmIdcState, kVBoxNetAdpWinIdcState_Stopping);
+ NdisReleaseSpinLock(&pGlobals->Lock);
+ Log(("vboxNetAdpWinUnload: IDC state change %s -> Stopping\n", vboxNetAdpWinIdcStateToText(enmPrevState)));
+
+ switch (enmPrevState)
+ {
+ case kVBoxNetAdpWinIdcState_Disconnected:
+ /* Have not even attempted to connect -- nothing to do. */
+ break;
+ case kVBoxNetAdpWinIdcState_Stopping:
+ /* Impossible, but another thread is alreading doing StopIdc, bail out */
+ LogError(("vboxNetAdpWinUnload: called in 'Stopping' state\n"));
+ break;
+ case kVBoxNetAdpWinIdcState_Connecting:
+ /* the worker thread is running, let's wait for it to stop */
+ Status = ObReferenceObjectByHandle(g_VBoxNetAdpGlobals.hInitIdcThread,
+ THREAD_ALL_ACCESS, NULL, KernelMode,
+ (PVOID*)&pThread, NULL);
+ if (Status == STATUS_SUCCESS)
+ {
+ KeWaitForSingleObject(pThread, Executive, KernelMode, FALSE, NULL);
+ ObDereferenceObject(pThread);
+ }
+ else
+ {
+ LogError(("vboxNetAdpWinStopIdc: ObReferenceObjectByHandle(%p) failed with 0x%x\n",
+ g_VBoxNetAdpGlobals.hInitIdcThread, Status));
+ }
+ break;
+ case kVBoxNetAdpWinIdcState_Connected:
+ /* the worker succeeded in IDC init and terminated */
+ /* Make sure nobody uses the trunk factory. Wait half a second if needed. */
+ if (!NdisWaitEvent(&pGlobals->EventUnloadAllowed, 500))
+ LogRel(("VBoxNetAdp: unloading driver while trunk factory is in use!\n"));
+ rc = SUPR0IdcComponentDeregisterFactory(&pGlobals->SupDrvIDC, &pGlobals->SupDrvFactory);
+ AssertRC(rc);
+ SUPR0IdcClose(&pGlobals->SupDrvIDC);
+ Log(("vboxNetAdpWinUnload: closed IDC, rc=0x%x\n", rc));
+ break;
+ }
+ if (pGlobals->hMiniportDriver)
+ NdisMDeregisterMiniportDriver(pGlobals->hMiniportDriver);
+ NdisFreeSpinLock(&pGlobals->Lock);
+ LogFlow(("<==vboxNetAdpWinUnload\n"));
+ RTLogDestroy(RTLogRelSetDefaultInstance(NULL));
+ RTLogDestroy(RTLogSetDefaultInstance(NULL));
+ RTR0Term();
+}
+
+
+/**
+ * register the miniport driver
+ */
+DECLHIDDEN(NDIS_STATUS) vboxNetAdpWinRegister(PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPathStr)
+{
+ NDIS_MINIPORT_DRIVER_CHARACTERISTICS MChars;
+
+ NdisZeroMemory(&MChars, sizeof (MChars));
+
+ MChars.Header.Type = NDIS_OBJECT_TYPE_MINIPORT_DRIVER_CHARACTERISTICS;
+ MChars.Header.Size = sizeof(NDIS_MINIPORT_DRIVER_CHARACTERISTICS);
+ MChars.Header.Revision = NDIS_MINIPORT_DRIVER_CHARACTERISTICS_REVISION_1;
+
+ MChars.MajorNdisVersion = VBOXNETADP_VERSION_NDIS_MAJOR;
+ MChars.MinorNdisVersion = VBOXNETADP_VERSION_NDIS_MINOR;
+
+ MChars.MajorDriverVersion = VBOXNETADP_VERSION_MAJOR;
+ MChars.MinorDriverVersion = VBOXNETADP_VERSION_MINOR;
+
+ MChars.InitializeHandlerEx = vboxNetAdpWinInitializeEx;
+ MChars.HaltHandlerEx = vboxNetAdpWinHaltEx;
+ MChars.UnloadHandler = vboxNetAdpWinUnload;
+ MChars.PauseHandler = vboxNetAdpWinPause;
+ MChars.RestartHandler = vboxNetAdpWinRestart;
+ MChars.OidRequestHandler = vboxNetAdpWinOidRequest;
+ MChars.SendNetBufferListsHandler = vboxNetAdpWinSendNetBufferLists;
+ MChars.ReturnNetBufferListsHandler = vboxNetAdpWinReturnNetBufferLists;
+ MChars.CancelSendHandler = vboxNetAdpWinCancelSend;
+ MChars.CheckForHangHandlerEx = vboxNetAdpWinCheckForHangEx;
+ MChars.ResetHandlerEx = vboxNetAdpWinResetEx;
+ MChars.DevicePnPEventNotifyHandler = vboxNetAdpWinDevicePnPEventNotify;
+ MChars.ShutdownHandlerEx = vboxNetAdpWinShutdownEx;
+ MChars.CancelOidRequestHandler = vboxNetAdpWinCancelOidRequest;
+
+ NDIS_STATUS Status;
+ g_VBoxNetAdpGlobals.hMiniportDriver = NULL;
+ Log(("vboxNetAdpWinRegister: registering miniport driver...\n"));
+ Status = NdisMRegisterMiniportDriver(pDriverObject,
+ pRegistryPathStr,
+ (NDIS_HANDLE)&g_VBoxNetAdpGlobals,
+ &MChars,
+ &g_VBoxNetAdpGlobals.hMiniportDriver);
+ Assert(Status == STATUS_SUCCESS);
+ if (Status == STATUS_SUCCESS)
+ {
+ Log(("vboxNetAdpWinRegister: successfully registered miniport driver; registering device...\n"));
+ }
+ else
+ {
+ Log(("ERROR! vboxNetAdpWinRegister: failed to register miniport driver, status=0x%x", Status));
+ }
+ return Status;
+}
+
+
+RT_C_DECLS_BEGIN
+
+NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath);
+
+RT_C_DECLS_END
+
+NTSTATUS DriverEntry(IN PDRIVER_OBJECT pDriverObject, IN PUNICODE_STRING pRegistryPath)
+{
+ NDIS_STATUS Status = NDIS_STATUS_SUCCESS;
+ int rc;
+
+
+ rc = RTR0Init(0);
+ AssertRC(rc);
+ if (RT_SUCCESS(rc))
+ {
+ NdisZeroMemory(&g_VBoxNetAdpGlobals, sizeof (g_VBoxNetAdpGlobals));
+ RTListInit(&g_VBoxNetAdpGlobals.ListOfAdapters);
+ NdisAllocateSpinLock(&g_VBoxNetAdpGlobals.Lock);
+ NdisInitializeEvent(&g_VBoxNetAdpGlobals.EventUnloadAllowed);
+ //g_VBoxNetAdpGlobals.PMCaps.WakeUpCapabilities.Flags = NDIS_DEVICE_WAKE_UP_ENABLE;
+ g_VBoxNetAdpGlobals.PMCaps.WakeUpCapabilities.MinMagicPacketWakeUp = NdisDeviceStateUnspecified;
+ g_VBoxNetAdpGlobals.PMCaps.WakeUpCapabilities.MinPatternWakeUp = NdisDeviceStateUnspecified;
+
+ /* Initialize SupDrv interface */
+ g_VBoxNetAdpGlobals.SupDrvFactory.pfnQueryFactoryInterface = vboxNetAdpWinQueryFactoryInterface;
+ memcpy(g_VBoxNetAdpGlobals.SupDrvFactory.szName, "VBoxNetAdp", sizeof("VBoxNetAdp"));
+ /* Initialize trunk factory interface */
+ g_VBoxNetAdpGlobals.TrunkFactory.pfnRelease = vboxNetAdpWinFactoryRelease;
+ g_VBoxNetAdpGlobals.TrunkFactory.pfnCreateAndConnect = vboxNetAdpWinFactoryCreateAndConnect;
+
+ rc = vboxNetAdpWinStartInitIdcThread(&g_VBoxNetAdpGlobals);
+ if (RT_SUCCESS(rc))
+ {
+ Status = vboxNetAdpWinRegister(pDriverObject, pRegistryPath);
+ Assert(Status == STATUS_SUCCESS);
+ if (Status == NDIS_STATUS_SUCCESS)
+ {
+ Log(("NETADP: started successfully\n"));
+ return STATUS_SUCCESS;
+ }
+ }
+ else
+ Status = NDIS_STATUS_FAILURE;
+ NdisFreeSpinLock(&g_VBoxNetAdpGlobals.Lock);
+ RTLogDestroy(RTLogRelSetDefaultInstance(NULL));
+ RTLogDestroy(RTLogSetDefaultInstance(NULL));
+
+ RTR0Term();
+ }
+ else
+ {
+ Status = NDIS_STATUS_FAILURE;
+ }
+
+ return Status;
+}
+
diff --git a/src/VBox/HostDrivers/VBoxNetAdp/win/VBoxNetAdp-win.h b/src/VBox/HostDrivers/VBoxNetAdp/win/VBoxNetAdp-win.h
new file mode 100644
index 00000000..31cebb2f
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetAdp/win/VBoxNetAdp-win.h
@@ -0,0 +1,71 @@
+/* $Id: VBoxNetAdp-win.h $ */
+/** @file
+ * VBoxNetAdp-win.h - Host-only Miniport Driver, Windows-specific code.
+ */
+/*
+ * Copyright (C) 2014-2022 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+#ifndef VBOX_INCLUDED_SRC_VBoxNetAdp_win_VBoxNetAdp_win_h
+#define VBOX_INCLUDED_SRC_VBoxNetAdp_win_VBoxNetAdp_win_h
+#ifndef RT_WITHOUT_PRAGMA_ONCE
+# pragma once
+#endif
+
+#define VBOXNETADP_VERSION_NDIS_MAJOR 6
+#define VBOXNETADP_VERSION_NDIS_MINOR 0
+
+#define VBOXNETADP_VERSION_MAJOR 1
+#define VBOXNETADP_VERSION_MINOR 0
+
+#define VBOXNETADP_VENDOR_NAME "Oracle"
+#define VBOXNETADP_VENDOR_ID 0xFFFFFF
+#define VBOXNETADP_MCAST_LIST_SIZE 32
+#define VBOXNETADP_MAX_FRAME_SIZE 1518 // TODO: 14+4+1500
+
+//#define VBOXNETADP_NAME_UNIQUE L"{7af6b074-048d-4444-bfce-1ecc8bc5cb76}"
+#define VBOXNETADP_NAME_SERVICE L"VBoxNetAdp"
+
+#define VBOXNETADP_NAME_LINK L"\\DosDevices\\Global\\VBoxNetAdp"
+#define VBOXNETADP_NAME_DEVICE L"\\Device\\VBoxNetAdp"
+
+#define VBOXNETADPWIN_TAG 'ANBV'
+
+#define VBOXNETADPWIN_ATTR_FLAGS NDIS_MINIPORT_ATTRIBUTES_NDIS_WDM | NDIS_MINIPORT_ATTRIBUTES_NO_HALT_ON_SUSPEND
+#define VBOXNETADP_MAC_OPTIONS NDIS_MAC_OPTION_NO_LOOPBACK
+#define VBOXNETADP_SUPPORTED_FILTERS (NDIS_PACKET_TYPE_DIRECTED | \
+ NDIS_PACKET_TYPE_MULTICAST | \
+ NDIS_PACKET_TYPE_BROADCAST | \
+ NDIS_PACKET_TYPE_PROMISCUOUS | \
+ NDIS_PACKET_TYPE_ALL_MULTICAST)
+#define VBOXNETADPWIN_SUPPORTED_STATISTICS 0 //TODO!
+#define VBOXNETADPWIN_HANG_CHECK_TIME 4
+
+#endif /* !VBOX_INCLUDED_SRC_VBoxNetAdp_win_VBoxNetAdp_win_h */
diff --git a/src/VBox/HostDrivers/VBoxNetAdp/win/VBoxNetAdp-win.rc b/src/VBox/HostDrivers/VBoxNetAdp/win/VBoxNetAdp-win.rc
new file mode 100644
index 00000000..c9eade4b
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetAdp/win/VBoxNetAdp-win.rc
@@ -0,0 +1,72 @@
+/* $Id: VBoxNetAdp-win.rc $ */
+/** @file
+ * VBoxNetAdp6 - Resource file containing version info and icon.
+ */
+/*
+ * Copyright (C) 2014-2022 Oracle and/or its affiliates.
+ *
+ * This file is part of VirtualBox base platform packages, as
+ * available from https://www.virtualbox.org.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation, in version 3 of the
+ * License.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, see <https://www.gnu.org/licenses>.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+ * in the VirtualBox distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ *
+ * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+ */
+
+#include <windows.h>
+#include <VBox/version.h>
+
+#define DESCRIPTION_STR "VirtualBox NDIS 6.0 Host-Only Network Adapter Driver\0"
+#define FILENAME_STR "VBoxNetAdp6"
+
+LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US
+
+VS_VERSION_INFO VERSIONINFO
+ FILEVERSION VBOX_RC_FILE_VERSION
+ PRODUCTVERSION VBOX_RC_FILE_VERSION
+ FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
+ FILEFLAGS VBOX_RC_FILE_FLAGS
+ FILEOS VBOX_RC_FILE_OS
+ FILETYPE VBOX_RC_TYPE_DRV
+ FILESUBTYPE VFT2_DRV_NETWORK
+BEGIN
+ BLOCK "StringFileInfo"
+ BEGIN
+ BLOCK "040904b0"
+ BEGIN
+ VALUE "FileDescription", DESCRIPTION_STR
+ VALUE "InternalName", FILENAME_STR "\0"
+ VALUE "OriginalFilename", FILENAME_STR ".sys\0"
+ VALUE "CompanyName", VBOX_RC_COMPANY_NAME
+ VALUE "FileVersion", VBOX_RC_FILE_VERSION_STR
+ VALUE "LegalCopyright", VBOX_RC_LEGAL_COPYRIGHT
+ VALUE "ProductName", VBOX_RC_PRODUCT_NAME_STR
+ VALUE "ProductVersion", VBOX_RC_PRODUCT_VERSION_STR
+ VBOX_RC_MORE_STRINGS
+ END
+ END
+ BLOCK "VarFileInfo"
+ BEGIN
+ VALUE "Translation", 0x409, 1200
+ END
+END
diff --git a/src/VBox/HostDrivers/VBoxNetAdp/win/VBoxNetAdp6.inf b/src/VBox/HostDrivers/VBoxNetAdp/win/VBoxNetAdp6.inf
new file mode 100644
index 00000000..02309059
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetAdp/win/VBoxNetAdp6.inf
@@ -0,0 +1,107 @@
+; $Id: VBoxNetAdp6.inf $
+;; @file
+; VBoxNetAdp6.inf - VirtualBox NDIS6 Miniport Driver inf file
+;
+; Note: We use the same component id as the old NetAdp implementation ?
+;
+
+;
+; Copyright (C) 2014-2022 Oracle and/or its affiliates.
+;
+; This file is part of VirtualBox base platform packages, as
+; available from https://www.virtualbox.org.
+;
+; This program is free software; you can redistribute it and/or
+; modify it under the terms of the GNU General Public License
+; as published by the Free Software Foundation, in version 3 of the
+; License.
+;
+; This program is distributed in the hope that it will be useful, but
+; WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+; General Public License for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with this program; if not, see <https://www.gnu.org/licenses>.
+;
+; The contents of this file may alternatively be used under the terms
+; of the Common Development and Distribution License Version 1.0
+; (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
+; in the VirtualBox distribution, in which case the provisions of the
+; CDDL are applicable instead of those of the GPL.
+;
+; You may elect to license modified versions of this file under the
+; terms and conditions of either the GPL or the CDDL or both.
+;
+; SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
+;
+
+[Version]
+Signature = "$Windows NT$"
+;cat CatalogFile = VBoxNetAdp6.cat
+Class = Net
+ClassGUID = {4D36E972-E325-11CE-BFC1-08002BE10318}
+Provider = %Provider%
+;edit-DriverVer=10/23/2014,1.0.1.0
+
+
+[Manufacturer]
+%Provider% = VBox,NTx86,NTamd64
+
+[ControlFlags]
+
+[VBox]
+%VBoxNetAdp6_Desc% = VBoxNetAdp6.ndi, sun_VBoxNetAdp
+
+[VBox.NTx86]
+%VBoxNetAdp6_Desc% = VBoxNetAdp6.ndi, sun_VBoxNetAdp
+
+[VBox.NTamd64]
+%VBoxNetAdp6_Desc% = VBoxNetAdp6.ndi, sun_VBoxNetAdp
+
+[VBoxNetAdp6.ndi]
+AddReg = VBoxNetAdp6.ndi.AddReg
+Characteristics = 0x1 ; NCF_VIRTUAL
+*IfType = 0x6 ; IF_TYPE_ETHERNET_CSMACD
+*MediaType = 0x0 ; NdisMedium802_3
+*PhysicalMediaType = 14 ; NdisPhysicalMedium802_3
+CopyFiles = VBoxNetAdp6.Files.Sys
+
+[VBoxNetAdp6.ndi.Services]
+AddService = VBoxNetAdp, 2, VBoxNetAdp6.AddService
+
+[VBoxNetAdp6.AddService]
+DisplayName = %VBoxNetAdp6Service_Desc%
+ServiceType = 1 ;SERVICE_KERNEL_DRIVER
+StartType = 3 ;SERVICE_DEMAND_START
+ErrorControl = 1 ;SERVICE_ERROR_NORMAL
+ServiceBinary = %12%\VBoxNetAdp6.sys
+LoadOrderGroup = NDIS
+
+[SourceDisksNames]
+1=%DiskDescription%,"",,
+
+[SourceDisksFiles]
+VBoxNetAdp6.sys=1
+
+[DestinationDirs]
+DefaultDestDir = 12
+VBoxNetAdp6.Files.Sys = 12 ; %windir%\System32\drivers
+
+[VBoxNetAdp6.Files.Sys]
+VBoxNetAdp6.sys,,,2
+
+[VBoxNetAdp6.ndi.AddReg]
+HKR, , *NdisDeviceType, 0x00010001, 1 ; NDIS_DEVICE_TYPE_ENDPOINT
+HKR, , BusNumber, 0, "0"
+HKR, Ndi, Service, 0, VBoxNetAdp
+HKR, Ndi, HelpText, , %VBoxNetAdp6_HELP%
+HKR, Ndi\Interfaces, UpperRange, 0, ndis5
+HKR, Ndi\Interfaces, LowerRange, 0, ethernet
+
+[Strings]
+Provider = "Oracle Corporation"
+DiskDescription = "VirtualBox NDIS 6.0 Miniport Driver"
+VBoxNetAdp6_Desc = "VirtualBox Host-Only Ethernet Adapter"
+VBoxNetAdp6_HELP = "VirtualBox NDIS 6.0 Miniport Driver"
+VBoxNetAdp6Service_Desc = "VirtualBox NDIS 6.0 Miniport Service"