diff --git a/repos/ports/lib/mk/spec/x86_64/virtualbox6-devices.mk b/repos/ports/lib/mk/spec/x86_64/virtualbox6-devices.mk
index 88b189a833..ca52f34ca9 100644
--- a/repos/ports/lib/mk/spec/x86_64/virtualbox6-devices.mk
+++ b/repos/ports/lib/mk/spec/x86_64/virtualbox6-devices.mk
@@ -41,7 +41,6 @@ SRC_CC += Devices/Network/DevEEPROM.cpp
SRC_CC += Devices/Network/DevPCNet.cpp
SRC_CC += Devices/Network/DrvNetShaper.cpp
SRC_CC += Devices/Network/DrvNetSniffer.cpp
-SRC_CC += Devices/Network/DrvTAP.cpp
SRC_CC += Devices/Network/Pcap.cpp
SRC_CC += Devices/Parallel/DevParallel.cpp
SRC_CC += Devices/PC/ACPI/VBoxAcpi.cpp
diff --git a/repos/ports/ports/virtualbox6.hash b/repos/ports/ports/virtualbox6.hash
index 69f0a04f07..e1f92e75e6 100644
--- a/repos/ports/ports/virtualbox6.hash
+++ b/repos/ports/ports/virtualbox6.hash
@@ -1 +1 @@
-c9f6708c2753758e31b59eb38dc1abcca821a913
+53f753241f3d5253338f284aa833d7db04469026
diff --git a/repos/ports/src/virtualbox6/init.h b/repos/ports/src/virtualbox6/init.h
index 920b7c2ef0..71eece96b9 100644
--- a/repos/ports/src/virtualbox6/init.h
+++ b/repos/ports/src/virtualbox6/init.h
@@ -19,4 +19,6 @@ namespace Genode { struct Env; }
namespace Sup { void init(Genode::Env &); }
+namespace Network { void init(Genode::Env &); }
+
#endif /* _INIT_H_ */
diff --git a/repos/ports/src/virtualbox6/main.cc b/repos/ports/src/virtualbox6/main.cc
index 6902b03e1c..1c49d5c2b3 100644
--- a/repos/ports/src/virtualbox6/main.cc
+++ b/repos/ports/src/virtualbox6/main.cc
@@ -338,6 +338,8 @@ void Libc::Component::construct(Libc::Env &env)
environ = envp;
+ Network::init(env);
+
/* sidestep 'rtThreadPosixSelectPokeSignal' */
uint32_t const fFlags = RTR3INIT_FLAGS_UNOBTRUSIVE;
diff --git a/repos/ports/src/virtualbox6/network.cc b/repos/ports/src/virtualbox6/network.cc
new file mode 100644
index 0000000000..cb49234e91
--- /dev/null
+++ b/repos/ports/src/virtualbox6/network.cc
@@ -0,0 +1,605 @@
+/**
+ * Genode network session driver,
+ * derived from src/VBox/Devices/Network/DrvTAP.cpp.
+ */
+
+/*
+ * Copyright (C) 2014-2021 Genode Labs GmbH
+ *
+ * This file is distributed under the terms of the GNU General Public License
+ * version 2.
+ */
+
+/*
+ * Copyright (C) 2006-2012 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ */
+
+/*******************************************************************************
+* Header Files *
+*******************************************************************************/
+#define LOG_GROUP LOG_GROUP_DRV_TUN
+#include
+#include
+#include
+#include
+#include
+
+#include
+
+#include
+#include
+
+#include "VBoxDD.h"
+
+#include
+#include
+
+#include
+
+/* VBox Genode specific */
+#include
+#include
+#include "init.h"
+
+/*******************************************************************************
+* Structures and Typedefs *
+*******************************************************************************/
+
+struct Nic_client;
+
+/**
+ * Nic driver instance data.
+ *
+ * @implements PDMINETWORKUP
+ */
+typedef struct DRVNIC
+{
+ /** The network interface to Nic session. */
+ PDMINETWORKUP INetworkUp;
+ /** The config port interface we're representing. */
+ PDMINETWORKCONFIG INetworkConfig;
+ /** The network interface to VBox driver. */
+ PPDMINETWORKDOWN pIAboveNet;
+ /** The config port interface we're attached to. */
+ PPDMINETWORKCONFIG pIAboveConfig;
+ /** Pointer to the driver instance. */
+ PPDMDRVINS pDrvIns;
+ /** Receiver thread that handles all signals. */
+ PPDMTHREAD pThread;
+ /** Nic::Session client wrapper. */
+ Nic_client *nic_client;
+} DRVNIC, *PDRVNIC;
+
+
+/**
+ * Return lock to synchronize the destruction of the
+ * PDRVNIC, i.e., the Nic_client.
+ */
+static Genode::Blockade &destruct_blockade()
+{
+ static Genode::Blockade blockade { };
+ return blockade;
+}
+
+
+static Genode::Allocator & net_alloc()
+{
+ static Libc::Allocator alloc { };
+ return alloc;
+}
+
+static Genode::Env *env_ptr = nullptr;
+
+void Network::init(Genode::Env &env)
+{
+ env_ptr = &env;
+}
+
+class Nic_client
+{
+ private:
+
+ enum {
+ PACKET_SIZE = Nic::Packet_allocator::DEFAULT_PACKET_SIZE,
+ BUF_SIZE = Nic::Session::QUEUE_SIZE * PACKET_SIZE,
+ };
+
+ Nic::Packet_allocator *_tx_block_alloc;
+ Nic::Connection _nic;
+
+ enum { NIC_EP_STACK = 32u << 10, };
+ Genode::Entrypoint _ep;
+ pthread_t _pthread;
+
+ Genode::Signal_handler _link_state_dispatcher;
+ Genode::Signal_handler _rx_packet_avail_dispatcher;
+ Genode::Signal_handler _rx_ready_to_ack_dispatcher;
+ Genode::Signal_handler _destruct_dispatcher;
+
+ bool _link_up = false;
+
+ /* VM <-> device driver (down) <-> nic_client (up) <-> nic session */
+ PPDMINETWORKDOWN _down_rx;
+ PPDMINETWORKCONFIG _down_rx_config;
+
+ void _handle_rx_packet_avail()
+ {
+ while (_nic.rx()->packet_avail() && _nic.rx()->ready_to_ack()) {
+ Nic::Packet_descriptor rx_packet = _nic.rx()->get_packet();
+
+ char *rx_content = _nic.rx()->packet_content(rx_packet);
+
+ Libc::with_libc([&] () {
+ int rc = _down_rx->pfnWaitReceiveAvail(_down_rx, RT_INDEFINITE_WAIT);
+ if (RT_FAILURE(rc)) return;
+
+ rc = _down_rx->pfnReceive(_down_rx, rx_content, rx_packet.size());
+ AssertRC(rc);
+ });
+
+ _nic.rx()->acknowledge_packet(rx_packet);
+ }
+ }
+
+ void _handle_rx_ready_to_ack() { _handle_rx_packet_avail(); }
+
+ void _handle_link_state()
+ {
+ _link_up = _nic.link_state();
+
+ Libc::with_libc([&] () {
+ _down_rx_config->pfnSetLinkState(_down_rx_config,
+ _link_up ? PDMNETWORKLINKSTATE_UP
+ : PDMNETWORKLINKSTATE_DOWN);
+ });
+ }
+
+ void _handle_destruct()
+ {
+ _nic.link_state_sigh(Genode::Signal_context_capability());
+ _nic.rx_channel()->sigh_packet_avail(Genode::Signal_context_capability());
+ _nic.rx_channel()->sigh_ready_to_ack(Genode::Signal_context_capability());
+
+ destruct_blockade().wakeup();
+ }
+
+ void _tx_ack(bool block = false)
+ {
+ /* check for acknowledgements */
+ while (_nic.tx()->ack_avail() || block) {
+ Nic::Packet_descriptor acked_packet = _nic.tx()->get_acked_packet();
+ _nic.tx()->release_packet(acked_packet);
+ block = false;
+ }
+ }
+
+ Nic::Packet_descriptor _alloc_tx_packet(Genode::size_t len)
+ {
+ while (true) {
+ try {
+ Nic::Packet_descriptor packet = _nic.tx()->alloc_packet(len);
+ return packet;
+ } catch (Nic::Session::Tx::Source::Packet_alloc_failed) {
+ _tx_ack(true);
+ }
+ }
+ }
+
+ static Nic::Packet_allocator* _packet_allocator()
+ {
+ return new (net_alloc()) Nic::Packet_allocator(&net_alloc());
+ }
+
+ void _handle_pthread_registration()
+ {
+ Genode::Thread *myself = Genode::Thread::myself();
+ if (!myself || Libc::pthread_create(&_pthread, *myself, &myself)) {
+ Genode::error("network will not work - thread for pthread "
+ "registration invalid");
+ return;
+ }
+ }
+
+ Genode::Signal_handler _pthread_reg_sigh {
+ _ep, *this, &Nic_client::_handle_pthread_registration };
+
+ public:
+
+ Nic_client(Genode::Env &env, PDRVNIC drvtap, char const *label)
+ :
+ _tx_block_alloc(_packet_allocator()),
+ _nic(env, _tx_block_alloc, BUF_SIZE, BUF_SIZE, label),
+ _ep(env, NIC_EP_STACK, "nic_ep", Genode::Affinity::Location()),
+ _link_state_dispatcher(_ep, *this, &Nic_client::_handle_link_state),
+ _rx_packet_avail_dispatcher(_ep, *this, &Nic_client::_handle_rx_packet_avail),
+ _rx_ready_to_ack_dispatcher(_ep, *this, &Nic_client::_handle_rx_ready_to_ack),
+ _destruct_dispatcher(_ep, *this, &Nic_client::_handle_destruct),
+ _down_rx(drvtap->pIAboveNet),
+ _down_rx_config(drvtap->pIAboveConfig)
+ {
+ Genode::Signal_transmitter(_pthread_reg_sigh).submit();
+ }
+
+ ~Nic_client()
+ {
+ /* XXX Libc::pthread_free(&_pthread); */
+ destroy(net_alloc(), _tx_block_alloc);
+ }
+
+ void enable_signals()
+ {
+ _nic.link_state_sigh(_link_state_dispatcher);
+ _nic.rx_channel()->sigh_packet_avail(_rx_packet_avail_dispatcher);
+ _nic.rx_channel()->sigh_ready_to_ack(_rx_ready_to_ack_dispatcher);
+
+ /* set initial link-state */
+ _handle_link_state();
+ }
+
+ Genode::Signal_context_capability dispatcher() { return _destruct_dispatcher; }
+ Nic::Mac_address mac_address() { return _nic.mac_address(); }
+
+ int send_packet(void *packet, uint32_t packet_len)
+ {
+ if (!_link_up) { return VERR_NET_DOWN; }
+
+ Nic::Packet_descriptor tx_packet = _alloc_tx_packet(packet_len);
+
+ char *tx_content = _nic.tx()->packet_content(tx_packet);
+ Genode::memcpy(tx_content, packet, packet_len);
+
+ _nic.tx()->submit_packet(tx_packet);
+ _tx_ack();
+
+ return VINF_SUCCESS;
+ }
+};
+
+
+/** Converts a pointer to Nic::INetworkUp to a PRDVNic. */
+#define PDMINETWORKUP_2_DRVNIC(pInterface) ( (PDRVNIC)((uintptr_t)pInterface - RT_OFFSETOF(DRVNIC, INetworkUp)) )
+#define PDMINETWORKCONFIG_2_DRVNIC(pInterface) ( (PDRVNIC)((uintptr_t)pInterface - RT_OFFSETOF(DRVNIC, INetworkConfig)) )
+
+
+/*******************************************************************************
+* Internal Functions *
+*******************************************************************************/
+
+/**
+ * @interface_method_impl{PDMINETWORKUP,pfnBeginXmit}
+ */
+static DECLCALLBACK(int) drvNicNetworkUp_BeginXmit(PPDMINETWORKUP pInterface, bool fOnWorkerThread)
+{
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * @interface_method_impl{PDMINETWORKUP,pfnAllocBuf}
+ */
+static DECLCALLBACK(int) drvNicNetworkUp_AllocBuf(PPDMINETWORKUP pInterface, size_t cbMin,
+ PCPDMNETWORKGSO pGso, PPPDMSCATTERGATHER ppSgBuf)
+{
+// PDRVNIC pThis = PDMINETWORKUP_2_DRVNIC(pInterface);
+
+ /*
+ * Allocate a scatter / gather buffer descriptor that is immediately
+ * followed by the buffer space of its single segment. The GSO context
+ * comes after that again.
+ */
+ PPDMSCATTERGATHER pSgBuf = (PPDMSCATTERGATHER)RTMemAlloc(RT_ALIGN_Z(sizeof(*pSgBuf), 16)
+ + RT_ALIGN_Z(cbMin, 16)
+ + (pGso ? RT_ALIGN_Z(sizeof(*pGso), 16) : 0));
+ if (!pSgBuf)
+ return VERR_NO_MEMORY;
+
+ /*
+ * Initialize the S/G buffer and return.
+ */
+ pSgBuf->fFlags = PDMSCATTERGATHER_FLAGS_MAGIC | PDMSCATTERGATHER_FLAGS_OWNER_1;
+ pSgBuf->cbUsed = 0;
+ pSgBuf->cbAvailable = RT_ALIGN_Z(cbMin, 16);
+ pSgBuf->pvAllocator = NULL;
+ if (!pGso)
+ pSgBuf->pvUser = NULL;
+ else
+ {
+ pSgBuf->pvUser = (uint8_t *)(pSgBuf + 1) + pSgBuf->cbAvailable;
+ *(PPDMNETWORKGSO)pSgBuf->pvUser = *pGso;
+ }
+ pSgBuf->cSegs = 1;
+ pSgBuf->aSegs[0].cbSeg = pSgBuf->cbAvailable;
+ pSgBuf->aSegs[0].pvSeg = pSgBuf + 1;
+
+ *ppSgBuf = pSgBuf;
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * @interface_method_impl{PDMINETWORKUP,pfnFreeBuf}
+ */
+static DECLCALLBACK(int) drvNicNetworkUp_FreeBuf(PPDMINETWORKUP pInterface, PPDMSCATTERGATHER pSgBuf)
+{
+// PDRVNIC pThis = PDMINETWORKUP_2_DRVNIC(pInterface);
+ if (pSgBuf)
+ {
+ Assert((pSgBuf->fFlags & PDMSCATTERGATHER_FLAGS_MAGIC_MASK) == PDMSCATTERGATHER_FLAGS_MAGIC);
+ pSgBuf->fFlags = 0;
+ RTMemFree(pSgBuf);
+ }
+ return VINF_SUCCESS;
+}
+
+
+/**
+ * @interface_method_impl{PDMINETWORKUP,pfnSendBuf}
+ */
+static DECLCALLBACK(int) drvNicNetworkUp_SendBuf(PPDMINETWORKUP pInterface, PPDMSCATTERGATHER pSgBuf, bool fOnWorkerThread)
+{
+ PDRVNIC pThis = PDMINETWORKUP_2_DRVNIC(pInterface);
+ Nic_client *nic_client = pThis->nic_client;
+
+ AssertPtr(pSgBuf);
+ Assert((pSgBuf->fFlags & PDMSCATTERGATHER_FLAGS_MAGIC_MASK) == PDMSCATTERGATHER_FLAGS_MAGIC);
+
+ /* Set an FTM checkpoint as this operation changes the state permanently. */
+// PDMDrvHlpFTSetCheckpoint(pThis->pDrvIns, FTMCHECKPOINTTYPE_NETWORK);
+
+ int rc;
+ if (!pSgBuf->pvUser)
+ {
+ Log2(("drvNicSend: pSgBuf->aSegs[0].pvSeg=%p pSgBuf->cbUsed=%#x\n"
+ "%.*Rhxd\n", pSgBuf->aSegs[0].pvSeg, pSgBuf->cbUsed, pSgBuf->cbUsed,
+ pSgBuf->aSegs[0].pvSeg));
+
+ rc = nic_client->send_packet(pSgBuf->aSegs[0].pvSeg, pSgBuf->cbUsed);
+ }
+ else
+ {
+ uint8_t abHdrScratch[256];
+ uint8_t const *pbFrame = (uint8_t const *)pSgBuf->aSegs[0].pvSeg;
+ PCPDMNETWORKGSO pGso = (PCPDMNETWORKGSO)pSgBuf->pvUser;
+ uint32_t const cSegs = PDMNetGsoCalcSegmentCount(pGso, pSgBuf->cbUsed);
+ Assert(cSegs > 1);
+ rc = VINF_SUCCESS;
+ for (size_t iSeg = 0; iSeg < cSegs; iSeg++)
+ {
+ uint32_t cbSegFrame;
+ void *pvSegFrame = PDMNetGsoCarveSegmentQD(pGso, (uint8_t *)pbFrame, pSgBuf->cbUsed,
+ abHdrScratch, iSeg, cSegs, &cbSegFrame);
+ rc = nic_client->send_packet(pvSegFrame, cbSegFrame);
+ if (RT_FAILURE(rc))
+ break;
+ }
+ }
+
+ pSgBuf->fFlags = 0;
+ RTMemFree(pSgBuf);
+
+ AssertRC(rc);
+ if (RT_FAILURE(rc))
+ rc = rc == VERR_NO_MEMORY ? VERR_NET_NO_BUFFER_SPACE : VERR_NET_DOWN;
+ return rc;
+}
+
+
+/**
+ * @interface_method_impl{PDMINETWORKUP,pfnEndXmit}
+ */
+static DECLCALLBACK(void) drvNicNetworkUp_EndXmit(PPDMINETWORKUP pInterface)
+{
+// PDRVNIC pThis = PDMINETWORKUP_2_DRVNIC(pInterface);
+}
+
+
+/**
+ * @interface_method_impl{PDMINETWORKUP,pfnSetPromiscuousMode}
+ */
+static DECLCALLBACK(void) drvNicNetworkUp_SetPromiscuousMode(PPDMINETWORKUP pInterface, bool fPromiscuous)
+{
+ LogFlow(("drvNicNetworkUp_SetPromiscuousMode: fPromiscuous=%d\n", fPromiscuous));
+ /* nothing to do */
+}
+
+
+/**
+ * Notification on link status changes.
+ */
+static DECLCALLBACK(void) drvNicNetworkUp_NotifyLinkChanged(PPDMINETWORKUP pInterface, PDMNETWORKLINKSTATE enmLinkState)
+{
+ LogFlow(("drvNicNetworkUp_NotifyLinkChanged: enmLinkState=%d\n", enmLinkState));
+ /*
+ * At this point we could stop waiting for signals etc. but for now we just do nothing.
+ */
+}
+
+
+static DECLCALLBACK(int) drvGetMac(PPDMINETWORKCONFIG pInterface, PRTMAC pMac)
+{
+ PDRVNIC pThis = PDMINETWORKCONFIG_2_DRVNIC(pInterface);
+ Nic_client *nic_client = pThis->nic_client;
+
+ static_assert (sizeof(*pMac) == sizeof(nic_client->mac_address()),
+ "should be equal");
+ memcpy(pMac, nic_client->mac_address().addr, sizeof(*pMac));
+ return VINF_SUCCESS;
+}
+
+
+/* -=-=-=-=- PDMIBASE -=-=-=-=- */
+
+/**
+ * @interface_method_impl{PDMIBASE,pfnQueryInterface}
+ */
+static DECLCALLBACK(void *) drvNicQueryInterface(PPDMIBASE pInterface, const char *pszIID)
+{
+ PPDMDRVINS pDrvIns = PDMIBASE_2_PDMDRV(pInterface);
+ PDRVNIC pThis = PDMINS_2_DATA(pDrvIns, PDRVNIC);
+
+ PDMIBASE_RETURN_INTERFACE(pszIID, PDMIBASE, &pDrvIns->IBase);
+ PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKUP, &pThis->INetworkUp);
+ PDMIBASE_RETURN_INTERFACE(pszIID, PDMINETWORKCONFIG, &pThis->INetworkConfig);
+ return NULL;
+}
+
+
+/* -=-=-=-=- PDMDRVREG -=-=-=-=- */
+
+static DECLCALLBACK(void) drvNicDestruct(PPDMDRVINS pDrvIns)
+{
+ PDRVNIC pThis = PDMINS_2_DATA(pDrvIns, PDRVNIC);
+ Nic_client *nic_client = pThis->nic_client;
+
+ if (!nic_client)
+ Genode::error("nic_client not valid at destruction time");
+
+ if (nic_client)
+ Genode::Signal_transmitter(nic_client->dispatcher()).submit();
+
+ /* wait until the recv thread exits */
+ destruct_blockade().block();
+
+ if (nic_client)
+ destroy(net_alloc(), nic_client);
+}
+
+
+/**
+ * Construct a Nic network transport driver instance.
+ *
+ * @copydoc FNPDMDRVCONSTRUCT
+ */
+static DECLCALLBACK(int) drvNicConstruct(PPDMDRVINS pDrvIns, PCFGMNODE pCfg, uint32_t fFlags)
+{
+ PDRVNIC pThis = PDMINS_2_DATA(pDrvIns, PDRVNIC);
+ PDMDRV_CHECK_VERSIONS_RETURN(pDrvIns);
+ int rc;
+
+ /*
+ * Init the static parts.
+ */
+ pThis->pDrvIns = pDrvIns;
+ /* IBase */
+ pDrvIns->IBase.pfnQueryInterface = drvNicQueryInterface;
+ /* INetwork */
+ pThis->INetworkUp.pfnBeginXmit = drvNicNetworkUp_BeginXmit;
+ pThis->INetworkUp.pfnAllocBuf = drvNicNetworkUp_AllocBuf;
+ pThis->INetworkUp.pfnFreeBuf = drvNicNetworkUp_FreeBuf;
+ pThis->INetworkUp.pfnSendBuf = drvNicNetworkUp_SendBuf;
+ pThis->INetworkUp.pfnEndXmit = drvNicNetworkUp_EndXmit;
+ pThis->INetworkUp.pfnSetPromiscuousMode = drvNicNetworkUp_SetPromiscuousMode;
+ pThis->INetworkUp.pfnNotifyLinkChanged = drvNicNetworkUp_NotifyLinkChanged;
+ /* INetworkConfig - used on Genode to request Mac address of nic_session */
+ pThis->INetworkConfig.pfnGetMac = drvGetMac;
+
+ /*
+ * Check that no-one is attached to us.
+ */
+ AssertMsgReturn(PDMDrvHlpNoAttach(pDrvIns) == VERR_PDM_NO_ATTACHED_DRIVER,
+ ("Configuration error: Not possible to attach anything to"
+ " this driver!\n"), VERR_PDM_DRVINS_NO_ATTACH);
+
+ /*
+ * Query the above network port interface.
+ */
+ pThis->pIAboveNet = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMINETWORKDOWN);
+ if (!pThis->pIAboveNet)
+ return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_ABOVE,
+ N_("Configuration error: The above device/driver"
+ " didn't export the network port interface"));
+ pThis->pIAboveConfig = PDMIBASE_QUERY_INTERFACE(pDrvIns->pUpBase, PDMINETWORKCONFIG);
+ if (!pThis->pIAboveConfig)
+ return PDMDRV_SET_ERROR(pDrvIns, VERR_PDM_MISSING_INTERFACE_ABOVE,
+ N_("Configuration error: the above device/driver"
+ " didn't export the network config interface!\n"));
+
+ uint64_t slot;
+ rc = CFGMR3QueryInteger(pCfg, "Slot", &slot);
+ if (RT_FAILURE(rc))
+ return PDMDRV_SET_ERROR(pDrvIns, rc,
+ N_("Configuration error: Failed to retrieve the network interface slot"));
+
+ Genode::String<9> label_string(slot);
+
+ /*
+ * Setup Genode nic_session connection
+ */
+ if (!env_ptr)
+ return VERR_HOSTIF_INIT_FAILED;
+
+ try {
+ pThis->nic_client = new (net_alloc()) Nic_client(*env_ptr, pThis, label_string.string());
+ } catch (...) {
+ return VERR_HOSTIF_INIT_FAILED;
+ }
+
+ return 0;
+}
+
+
+static DECLCALLBACK(void) drvNicPowerOn(PPDMDRVINS pDrvIns)
+{
+ PDRVNIC pThis = PDMINS_2_DATA(pDrvIns, PDRVNIC);
+
+ if (pThis && pThis->nic_client)
+ pThis->nic_client->enable_signals();
+}
+
+/**
+ * Nic network transport driver registration record.
+ */
+const PDMDRVREG g_DrvHostInterface =
+{
+ /* u32Version */
+ PDM_DRVREG_VERSION,
+ /* szName */
+ "HostInterface",
+ /* szRCMod */
+ "",
+ /* szR0Mod */
+ "",
+ /* pszDescription */
+ "Genode Network Session Driver",
+ /* fFlags */
+ PDM_DRVREG_FLAGS_HOST_BITS_DEFAULT,
+ /* fClass. */
+ PDM_DRVREG_CLASS_NETWORK,
+ /* cMaxInstances */
+ ~0U,
+ /* cbInstance */
+ sizeof(DRVNIC),
+ /* pfnConstruct */
+ drvNicConstruct,
+ /* pfnDestruct */
+ drvNicDestruct,
+ /* pfnRelocate */
+ NULL,
+ /* pfnIOCtl */
+ NULL,
+ drvNicPowerOn,
+ /* pfnReset */
+ NULL,
+ /* pfnSuspend */
+ NULL,
+ /* pfnResume */
+ NULL,
+ /* pfnAttach */
+ NULL,
+ /* pfnDetach */
+ NULL,
+ /* pfnPowerOff */
+ NULL,
+ /* pfnSoftReset */
+ NULL,
+ /* u32EndVersion */
+ PDM_DRVREG_VERSION
+};
diff --git a/repos/ports/src/virtualbox6/patches/drvtap.patch b/repos/ports/src/virtualbox6/patches/drvtap.patch
new file mode 100644
index 0000000000..ab802599d4
--- /dev/null
+++ b/repos/ports/src/virtualbox6/patches/drvtap.patch
@@ -0,0 +1,31 @@
+Disarm check for usable TUN/TAP file. On Genode the DrvTAP is implemented
+by network.cc and uses Genode nic_session directly.
+
+--- a/src/virtualbox6/src/VBox/Main/src-client/ConsoleImpl2.cpp
++++ b/src/virtualbox6/src/VBox/Main/src-client/ConsoleImpl2.cpp
+@@ -5255,18 +5255,24 @@
+ "sure that these changes are permanent, especially if you are "
+ "using udev"));
+ default:
++#if 0
+ AssertMsgFailed(("Could not attach to host interface! Bad!\n"));
+ return VMSetError(VMR3GetVM(mpUVM), VERR_HOSTIF_INIT_FAILED, RT_SRC_POS, N_(
+ "Failed to initialize Host Interface Networking"));
++#else
++ break;
++#endif
+ }
+ }
+
++#if 0
+ Assert((intptr_t)maTapFD[uInstance] >= 0);
+ if ((intptr_t)maTapFD[uInstance] >= 0)
++#endif
+ {
+ InsertConfigString(pLunL0, "Driver", "HostInterface");
+ InsertConfigNode(pLunL0, "Config", &pCfg);
+- InsertConfigInteger(pCfg, "FileHandle", (intptr_t)maTapFD[uInstance]);
++ InsertConfigInteger(pCfg, "Slot", uInstance);
+ }
+
+ #elif defined(VBOX_WITH_NETFLT)
diff --git a/repos/ports/src/virtualbox6/patches/series b/repos/ports/src/virtualbox6/patches/series
index 72b8487e74..b37d452ab8 100644
--- a/repos/ports/src/virtualbox6/patches/series
+++ b/repos/ports/src/virtualbox6/patches/series
@@ -1 +1,2 @@
serial.patch
+drvtap.patch
diff --git a/repos/ports/src/virtualbox6/target.mk b/repos/ports/src/virtualbox6/target.mk
index 7e5da19f84..73cee714a7 100644
--- a/repos/ports/src/virtualbox6/target.mk
+++ b/repos/ports/src/virtualbox6/target.mk
@@ -6,6 +6,7 @@ CC_WARN += -Wall
SRC_CC := main.cc drivers.cc vcpu_gim.cc
SRC_CC += libc.cc unimpl.cc dummies.cc pdm.cc devices.cc nem.cc dynlib.cc
+SRC_CC += network.cc
LIBS += base
LIBS += stdcxx