summaryrefslogtreecommitdiffstats
path: root/src/VBox/HostDrivers/VBoxNetFlt/solaris/VBoxNetFltBow-solaris.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/HostDrivers/VBoxNetFlt/solaris/VBoxNetFltBow-solaris.c')
-rw-r--r--src/VBox/HostDrivers/VBoxNetFlt/solaris/VBoxNetFltBow-solaris.c1702
1 files changed, 1702 insertions, 0 deletions
diff --git a/src/VBox/HostDrivers/VBoxNetFlt/solaris/VBoxNetFltBow-solaris.c b/src/VBox/HostDrivers/VBoxNetFlt/solaris/VBoxNetFltBow-solaris.c
new file mode 100644
index 00000000..4a717253
--- /dev/null
+++ b/src/VBox/HostDrivers/VBoxNetFlt/solaris/VBoxNetFltBow-solaris.c
@@ -0,0 +1,1702 @@
+/* $Id: VBoxNetFltBow-solaris.c $ */
+/** @file
+ * VBoxNetFlt - Network Filter Driver (Host), Solaris Specific Code.
+ */
+
+/*
+ * Copyright (C) 2008-2023 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_FLT_DRV
+#include <VBox/log.h>
+#include <VBox/err.h>
+#include <VBox/intnetinline.h>
+#include <VBox/version.h>
+#include <iprt/initterm.h>
+#include <iprt/alloca.h>
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/string.h>
+#include <iprt/rand.h>
+#include <iprt/net.h>
+#include <iprt/spinlock.h>
+#include <iprt/mem.h>
+
+#include <sys/types.h>
+#include <sys/modctl.h>
+#include <sys/conf.h>
+#include <sys/stat.h>
+#include <sys/ddi.h>
+#include <sys/gld.h>
+#include <sys/sunddi.h>
+#include <sys/strsubr.h>
+#include <sys/dlpi.h>
+#include <sys/dls_mgmt.h>
+#include <sys/mac.h>
+#include <sys/strsun.h>
+
+#include <sys/vnic_mgmt.h>
+#include <sys/mac_client.h>
+#include <sys/mac_provider.h>
+#include <sys/dls.h>
+#include <sys/dld.h>
+#include <sys/cred.h>
+
+
+#define VBOXNETFLT_OS_SPECFIC 1
+#include "../VBoxNetFltInternal.h"
+
+
+/*********************************************************************************************************************************
+* Defined Constants And Macros *
+*********************************************************************************************************************************/
+/** The module name. */
+#define DEVICE_NAME "vboxbow"
+/** The module descriptions as seen in 'modinfo'. */
+#define DEVICE_DESC_DRV "VirtualBox NetBow"
+/** The dynamically created VNIC name (hardcoded in NetIf-solaris.cpp).
+ * @todo move this define into a common header. */
+#define VBOXBOW_VNIC_NAME "vboxvnic"
+/** The VirtualBox VNIC template name (hardcoded in NetIf-solaris.cpp).
+ * @todo move this define into a common header. */
+#define VBOXBOW_VNIC_TEMPLATE_NAME "vboxvnic_template"
+/** Debugging switch for using symbols in kmdb */
+# define LOCAL static
+/** VBOXNETFLTVNIC::u32Magic */
+# define VBOXNETFLTVNIC_MAGIC 0x0ddfaced
+
+/** VLAN tag masking, should probably be in IPRT? */
+#define VLAN_ID(vlan) (((vlan) >> 0) & 0x0fffu)
+#define VLAN_CFI(vlan) (((vlan) >> 12) & 0x0001u)
+#define VLAN_PRI(vlan) (((vlan) >> 13) & 0x0007u)
+#define VLAN_TAG(pri,cfi,vid) (((pri) << 13) | ((cfi) << 12) | ((vid) << 0))
+
+typedef struct VLANHEADER
+{
+ uint16_t Type;
+ uint16_t Data;
+} VLANHEADER;
+typedef struct VLANHEADER *PVLANHEADER;
+
+/* Private: from sys/vlan.h */
+#ifndef VLAN_ID_NONE
+# define VLAN_ID_NONE 0
+#endif
+
+/* Private: from sys/param.h */
+#ifndef MAXLINKNAMESPECIFIER
+# define MAXLINKNAMESPECIFIER 96 /* MAXLINKNAMELEN + ZONENAME_MAX */
+#endif
+
+/* Private: from sys/mac_client_priv.h, mac client function prototypes. */
+extern uint16_t mac_client_vid(mac_client_handle_t hClient);
+extern void mac_client_get_resources(mac_client_handle_t hClient, mac_resource_props_t *pResources);
+extern int mac_client_set_resources(mac_client_handle_t hClient, mac_resource_props_t *pResources);
+
+
+/*********************************************************************************************************************************
+* Kernel Entry Hooks *
+*********************************************************************************************************************************/
+LOCAL int VBoxNetFltSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd);
+LOCAL int VBoxNetFltSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd);
+LOCAL int VBoxNetFltSolarisGetInfo(dev_info_t *pDip, ddi_info_cmd_t enmCmd, void *pArg, void **ppvResult);
+
+
+/*********************************************************************************************************************************
+* Structures and Typedefs *
+*********************************************************************************************************************************/
+/**
+ * cb_ops: for drivers that support char/block entry points
+ */
+static struct cb_ops g_VBoxNetFltSolarisCbOps =
+{
+ nulldev, /* c open */
+ nulldev, /* c close */
+ nodev, /* b strategy */
+ nodev, /* b dump */
+ nodev, /* b print */
+ nodev, /* c read */
+ nodev, /* c write*/
+ nodev, /* c ioctl*/
+ nodev, /* c devmap */
+ nodev, /* c mmap */
+ nodev, /* c segmap */
+ nochpoll, /* c poll */
+ ddi_prop_op, /* property ops */
+ NULL, /* streamtab */
+ D_NEW | D_MP, /* compat. flag */
+ CB_REV, /* revision */
+ nodev, /* c aread */
+ nodev /* c awrite */
+};
+
+/**
+ * dev_ops: for driver device operations
+ */
+static struct dev_ops g_VBoxNetFltSolarisDevOps =
+{
+ DEVO_REV, /* driver build revision */
+ 0, /* ref count */
+ VBoxNetFltSolarisGetInfo,
+ nulldev, /* identify */
+ nulldev, /* probe */
+ VBoxNetFltSolarisAttach,
+ VBoxNetFltSolarisDetach,
+ nodev, /* reset */
+ &g_VBoxNetFltSolarisCbOps,
+ NULL, /* bus ops */
+ nodev, /* power */
+ ddi_quiesce_not_needed
+};
+
+/**
+ * modldrv: export driver specifics to the kernel
+ */
+static struct modldrv g_VBoxNetFltSolarisModule =
+{
+ &mod_driverops, /* extern from kernel */
+ DEVICE_DESC_DRV " " VBOX_VERSION_STRING "r" RT_XSTR(VBOX_SVN_REV),
+ &g_VBoxNetFltSolarisDevOps
+};
+
+/**
+ * modlinkage: export install/remove/info to the kernel
+ */
+static struct modlinkage g_VBoxNetFltSolarisModLinkage =
+{
+ MODREV_1,
+ {
+ &g_VBoxNetFltSolarisModule,
+ NULL,
+ }
+};
+
+/*
+ * VBOXNETFLTVNICTEMPLATE: VNIC template information.
+ */
+typedef struct VBOXNETFLTVNICTEMPLATE
+{
+ /** The name of link on which the VNIC template is created on. */
+ char szLinkName[MAXNAMELEN];
+ /** The VLAN Id (can be VLAN_ID_NONE). */
+ uint16_t uVLANId;
+ /** Resources (bandwidth, CPU bindings, flow priority etc.) */
+ mac_resource_props_t Resources;
+} VBOXNETFLTVNICTEMPLATE;
+typedef struct VBOXNETFLTVNICTEMPLATE *PVBOXNETFLTVNICTEMPLATE;
+
+/**
+ * VBOXNETFLTVNIC: Per-VNIC instance data.
+ */
+typedef struct VBOXNETFLTVNIC
+{
+ /** Magic number (VBOXNETFLTVNIC_MAGIC). */
+ uint32_t u32Magic;
+ /** Whether we created the VNIC or not. */
+ bool fCreated;
+ /** Pointer to the VNIC template if any. */
+ PVBOXNETFLTVNICTEMPLATE pVNICTemplate;
+ /** Pointer to the VirtualBox interface instance. */
+ void *pvIf;
+ /** The MAC handle. */
+ mac_handle_t hInterface;
+ /** The VNIC link ID. */
+ datalink_id_t hLinkId;
+ /** The MAC client handle */
+ mac_client_handle_t hClient;
+ /** The unicast address handle. */
+ mac_unicast_handle_t hUnicast;
+ /** The promiscuous handle. */
+ mac_promisc_handle_t hPromisc;
+ /* The VNIC name. */
+ char szName[MAXLINKNAMESPECIFIER];
+ /** Handle to the next VNIC in the list. */
+ list_node_t hNode;
+} VBOXNETFLTVNIC;
+typedef struct VBOXNETFLTVNIC *PVBOXNETFLTVNIC;
+
+
+/*********************************************************************************************************************************
+* Global Variables *
+*********************************************************************************************************************************/
+/** Global Device handle we only support one instance. */
+static dev_info_t *g_pVBoxNetFltSolarisDip = NULL;
+/** The (common) global data. */
+static VBOXNETFLTGLOBALS g_VBoxNetFltSolarisGlobals;
+/** Global next-free VNIC Id (never decrements). */
+static volatile uint64_t g_VBoxNetFltSolarisVNICId;
+
+
+/*********************************************************************************************************************************
+* Internal Functions *
+*********************************************************************************************************************************/
+LOCAL mblk_t *vboxNetFltSolarisMBlkFromSG(PVBOXNETFLTINS pThis, PINTNETSG pSG, uint32_t fDst);
+LOCAL unsigned vboxNetFltSolarisMBlkCalcSGSegs(PVBOXNETFLTINS pThis, mblk_t *pMsg);
+LOCAL int vboxNetFltSolarisMBlkToSG(PVBOXNETFLTINS pThis, mblk_t *pMsg, PINTNETSG pSG, unsigned cSegs, uint32_t fSrc);
+LOCAL void vboxNetFltSolarisRecv(void *pvData, mac_resource_handle_t hResource, mblk_t *pMsg, boolean_t fLoopback);
+//LOCAL void vboxNetFltSolarisAnalyzeMBlk(mblk_t *pMsg);
+LOCAL int vboxNetFltSolarisReportInfo(PVBOXNETFLTINS pThis, mac_handle_t hInterface, bool fIsVNIC);
+LOCAL int vboxNetFltSolarisInitVNIC(PVBOXNETFLTINS pThis, PVBOXNETFLTVNIC pVNIC);
+LOCAL int vboxNetFltSolarisInitVNICTemplate(PVBOXNETFLTINS pThis, PVBOXNETFLTVNICTEMPLATE pVNICTemplate);
+LOCAL PVBOXNETFLTVNIC vboxNetFltSolarisAllocVNIC(void);
+LOCAL void vboxNetFltSolarisFreeVNIC(PVBOXNETFLTVNIC pVNIC);
+LOCAL void vboxNetFltSolarisDestroyVNIC(PVBOXNETFLTVNIC pVNIC);
+LOCAL int vboxNetFltSolarisCreateVNIC(PVBOXNETFLTINS pThis, PVBOXNETFLTVNIC *ppVNIC);
+DECLINLINE(int) vboxNetFltSolarisGetLinkId(const char *pszMacName, datalink_id_t *pLinkId);
+
+/**
+ * Kernel entry points
+ */
+int _init(void)
+{
+ Log((DEVICE_NAME ":_init\n"));
+
+ /*
+ * Prevent module autounloading.
+ */
+ modctl_t *pModCtl = mod_getctl(&g_VBoxNetFltSolarisModLinkage);
+ if (pModCtl)
+ pModCtl->mod_loadflags |= MOD_NOAUTOUNLOAD;
+ else
+ cmn_err(CE_NOTE, ":failed to disable autounloading!\n");
+
+ /*
+ * Initialize IPRT.
+ */
+ int rc = RTR0Init(0);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Initialize the globals and connect to the support driver.
+ *
+ * This will call back vboxNetFltOsOpenSupDrv (and maybe vboxNetFltOsCloseSupDrv)
+ * for establishing the connect to the support driver.
+ */
+ memset(&g_VBoxNetFltSolarisGlobals, 0, sizeof(g_VBoxNetFltSolarisGlobals));
+ rc = vboxNetFltInitGlobalsAndIdc(&g_VBoxNetFltSolarisGlobals);
+ if (RT_SUCCESS(rc))
+ {
+ rc = mod_install(&g_VBoxNetFltSolarisModLinkage);
+ if (!rc)
+ return rc;
+
+ LogRel((DEVICE_NAME ":mod_install failed. rc=%d\n", rc));
+ vboxNetFltTryDeleteIdcAndGlobals(&g_VBoxNetFltSolarisGlobals);
+ }
+ else
+ LogRel((DEVICE_NAME ":failed to initialize globals.\n"));
+
+ RTR0Term();
+ }
+ else
+ cmn_err(CE_NOTE, "failed to initialize IPRT (rc=%d)\n", rc);
+
+ memset(&g_VBoxNetFltSolarisGlobals, 0, sizeof(g_VBoxNetFltSolarisGlobals));
+ return RTErrConvertToErrno(rc);
+}
+
+
+int _fini(void)
+{
+ int rc;
+ Log((DEVICE_NAME ":_fini\n"));
+
+ /*
+ * Undo the work done during start (in reverse order).
+ */
+ rc = vboxNetFltTryDeleteIdcAndGlobals(&g_VBoxNetFltSolarisGlobals);
+ if (RT_FAILURE(rc))
+ {
+ LogRel((DEVICE_NAME ":_fini - busy! rc=%d\n", rc));
+ return EBUSY;
+ }
+
+ rc = mod_remove(&g_VBoxNetFltSolarisModLinkage);
+ if (!rc)
+ RTR0Term();
+
+ return rc;
+}
+
+
+int _info(struct modinfo *pModInfo)
+{
+ /* _info() can be called before _init() so RTR0Init() might not be called at this point. */
+ int rc = mod_info(&g_VBoxNetFltSolarisModLinkage, pModInfo);
+ 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.
+ */
+LOCAL int VBoxNetFltSolarisAttach(dev_info_t *pDip, ddi_attach_cmd_t enmCmd)
+{
+ Log((DEVICE_NAME ":VBoxNetFltSolarisAttach pDip=%p enmCmd=%d\n", pDip, enmCmd));
+
+ switch (enmCmd)
+ {
+ case DDI_ATTACH:
+ {
+ g_pVBoxNetFltSolarisDip = pDip;
+ return DDI_SUCCESS;
+ }
+
+ 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.
+ */
+LOCAL int VBoxNetFltSolarisDetach(dev_info_t *pDip, ddi_detach_cmd_t enmCmd)
+{
+ Log((DEVICE_NAME ":VBoxNetFltSolarisDetach pDip=%p enmCmd=%d\n", pDip, enmCmd));
+
+ switch (enmCmd)
+ {
+ case DDI_DETACH:
+ {
+ return DDI_SUCCESS;
+ }
+
+ case DDI_RESUME:
+ {
+ /* Nothing to do here... */
+ return DDI_SUCCESS;
+ }
+
+ /* case DDI_PM_SUSPEND: */
+ /* case DDI_HOT_PLUG_DETACH: */
+ default:
+ return DDI_FAILURE;
+ }
+}
+
+
+/**
+ * Info entry point, called by solaris kernel for obtaining driver info.
+ *
+ * @param pDip The module structure instance (do not use).
+ * @param enmCmd Information request type.
+ * @param pvArg Type specific argument.
+ * @param ppvResult Where to store the requested info.
+ *
+ * @returns corresponding solaris error code.
+ */
+LOCAL int VBoxNetFltSolarisGetInfo(dev_info_t *pDip, ddi_info_cmd_t enmCmd, void *pvArg, void **ppvResult)
+{
+ Log((DEVICE_NAME ":VBoxNetFltSolarisGetInfo pDip=%p enmCmd=%d pArg=%p instance=%d\n", pDip, enmCmd, getminor((dev_t)pvArg)));
+
+ switch (enmCmd)
+ {
+ case DDI_INFO_DEVT2DEVINFO:
+ {
+ *ppvResult = g_pVBoxNetFltSolarisDip;
+ return *ppvResult ? DDI_SUCCESS : DDI_FAILURE;
+ }
+
+ case DDI_INFO_DEVT2INSTANCE:
+ {
+ /* There can only be a single-instance of this driver and thus its instance number is 0. */
+ *ppvResult = (void *)0;
+ break;
+ }
+ }
+
+ return DDI_FAILURE;
+}
+
+
+/**
+ * Create a solaris message block from the SG list.
+ *
+ * @param pThis The instance.
+ * @param pSG Pointer to the scatter-gather list.
+ * @param fDst INTNETTRUNKDIR_XXX.
+ *
+ * @returns Solaris message block.
+ */
+DECLINLINE(mblk_t *) vboxNetFltSolarisMBlkFromSG(PVBOXNETFLTINS pThis, PINTNETSG pSG, uint32_t fDst)
+{
+ Log((DEVICE_NAME ":vboxNetFltSolarisMBlkFromSG pThis=%p pSG=%p\n", pThis, pSG));
+
+ mblk_t *pMsg = allocb(pSG->cbTotal, BPRI_HI);
+ if (RT_UNLIKELY(!pMsg))
+ {
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisMBlkFromSG failed to alloc %d bytes for mblk_t.\n", pSG->cbTotal));
+ return NULL;
+ }
+
+ /*
+ * Single buffer copy. Maybe later explore the
+ * need/possibility for using a mblk_t chain rather.
+ */
+ for (unsigned i = 0; i < pSG->cSegsUsed; i++)
+ {
+ if (pSG->aSegs[i].pv)
+ {
+ bcopy(pSG->aSegs[i].pv, pMsg->b_wptr, pSG->aSegs[i].cb);
+ pMsg->b_wptr += pSG->aSegs[i].cb;
+ }
+ }
+ return pMsg;
+}
+
+
+/**
+ * Calculate the number of segments required for this message block.
+ *
+ * @param pThis The instance
+ * @param pMsg Pointer to the data message.
+ *
+ * @returns Number of segments.
+ */
+LOCAL unsigned vboxNetFltSolarisMBlkCalcSGSegs(PVBOXNETFLTINS pThis, mblk_t *pMsg)
+{
+ unsigned cSegs = 0;
+ for (mblk_t *pCur = pMsg; pCur; pCur = pCur->b_cont)
+ if (MBLKL(pCur))
+ cSegs++;
+
+#ifdef PADD_RUNT_FRAMES_FROM_HOST
+ if (msgdsize(pMsg) < 60)
+ cSegs++;
+#endif
+
+ NOREF(pThis);
+ return RT_MAX(cSegs, 1);
+}
+
+
+/**
+ * Initializes an SG list from the given message block.
+ *
+ * @param pThis The instance.
+ * @param pMsg Pointer to the data message.
+ The caller must ensure it's not a control message block.
+ * @param pSG Pointer to the SG.
+ * @param cSegs Number of segments in the SG.
+ * This should match the number in the message block exactly!
+ * @param fSrc The source of the message.
+ *
+ * @returns VBox status code.
+ */
+LOCAL int vboxNetFltSolarisMBlkToSG(PVBOXNETFLTINS pThis, mblk_t *pMsg, PINTNETSG pSG, unsigned cSegs, uint32_t fSrc)
+{
+ Log((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG pThis=%p pMsg=%p pSG=%p cSegs=%d\n", pThis, pMsg, pSG, cSegs));
+
+ /*
+ * Convert the message block to segments. Works cbTotal and sets cSegsUsed.
+ */
+ IntNetSgInitTempSegs(pSG, 0 /*cbTotal*/, cSegs, 0 /*cSegsUsed*/);
+ mblk_t *pCur = pMsg;
+ unsigned iSeg = 0;
+ while (pCur)
+ {
+ size_t cbSeg = MBLKL(pCur);
+ if (cbSeg)
+ {
+ void *pvSeg = pCur->b_rptr;
+ pSG->aSegs[iSeg].pv = pvSeg;
+ pSG->aSegs[iSeg].cb = cbSeg;
+ pSG->aSegs[iSeg].Phys = NIL_RTHCPHYS;
+ pSG->cbTotal += cbSeg;
+ iSeg++;
+ }
+ pCur = pCur->b_cont;
+ }
+ pSG->cSegsUsed = iSeg;
+
+#ifdef PADD_RUNT_FRAMES_FROM_HOST
+ if (pSG->cbTotal < 60 && (fSrc & INTNETTRUNKDIR_HOST))
+ {
+ Log((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG pulling up to length.\n"));
+
+ static uint8_t const s_abZero[128] = {0};
+ pSG->aSegs[iSeg].Phys = NIL_RTHCPHYS;
+ pSG->aSegs[iSeg].pv = (void *)&s_abZero[0];
+ pSG->aSegs[iSeg].cb = 60 - pSG->cbTotal;
+ pSG->cbTotal = 60;
+ pSG->cSegsUsed++;
+ Assert(iSeg + 1 < cSegs);
+ }
+#endif
+
+ Log((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG iSeg=%d pSG->cbTotal=%d msgdsize=%d\n", iSeg, pSG->cbTotal, msgdsize(pMsg)));
+ return VINF_SUCCESS;
+}
+
+
+#if 0
+/**
+ * Simple packet dump, used for internal debugging.
+ *
+ * @param pMsg Pointer to the message to analyze and dump.
+ */
+LOCAL void vboxNetFltSolarisAnalyzeMBlk(mblk_t *pMsg)
+{
+ LogFunc((DEVICE_NAME ":vboxNetFltSolarisAnalyzeMBlk pMsg=%p\n", pMsg));
+
+ PCRTNETETHERHDR pEthHdr = (PCRTNETETHERHDR)pMsg->b_rptr;
+ uint8_t *pb = pMsg->b_rptr;
+ if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPV4))
+ {
+ PRTNETIPV4 pIpHdr = (PRTNETIPV4)(pEthHdr + 1);
+ if (!pMsg->b_cont)
+ {
+ if (pIpHdr->ip_p == RTNETIPV4_PROT_ICMP)
+ LogRel((DEVICE_NAME ":ICMP D=%.6Rhxs S=%.6Rhxs T=%04x\n", pb, pb + 6, RT_BE2H_U16(*(uint16_t *)(pb + 12))));
+ else if (pIpHdr->ip_p == RTNETIPV4_PROT_TCP)
+ LogRel((DEVICE_NAME ":TCP D=%.6Rhxs S=%.6Rhxs\n", pb, pb + 6));
+ else if (pIpHdr->ip_p == RTNETIPV4_PROT_UDP)
+ {
+ PCRTNETUDP pUdpHdr = (PCRTNETUDP)((uint32_t *)pIpHdr + pIpHdr->ip_hl);
+ if ( RT_BE2H_U16(pUdpHdr->uh_sport) == 67
+ && RT_BE2H_U16(pUdpHdr->uh_dport) == 68)
+ {
+ LogRel((DEVICE_NAME ":UDP bootp ack D=%.6Rhxs S=%.6Rhxs UDP_CheckSum=%04x Computex=%04x\n", pb, pb + 6,
+ RT_BE2H_U16(pUdpHdr->uh_sum), RT_BE2H_U16(RTNetIPv4UDPChecksum(pIpHdr, pUdpHdr, pUdpHdr + 1))));
+ }
+ }
+ }
+ else
+ {
+ Log((DEVICE_NAME ":Chained IP packet. Skipping validity check.\n"));
+ }
+ }
+ else if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_VLAN))
+ {
+ PVLANHEADER pVlanHdr = (PVLANHEADER)(pMsg->b_rptr + sizeof(RTNETETHERHDR) - sizeof(pEthHdr->EtherType));
+ LogRel((DEVICE_NAME ":VLAN Pcp=%u Cfi=%u Id=%u\n", VLAN_PRI(RT_BE2H_U16(pVlanHdr->Data)),
+ VLAN_CFI(RT_BE2H_U16(pVlanHdr->Data)), VLAN_ID(RT_BE2H_U16(pVlanHdr->Data))));
+ LogRel((DEVICE_NAME "%.*Rhxd\n", sizeof(VLANHEADER), pVlanHdr));
+ }
+ else if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_ARP))
+ {
+ PRTNETARPHDR pArpHdr = (PRTNETARPHDR)(pEthHdr + 1);
+ LogRel((DEVICE_NAME ":ARP Op=%d\n", pArpHdr->ar_oper));
+ }
+ else if (pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPV6))
+ {
+ LogRel((DEVICE_NAME ":IPv6 D=%.6Rhxs S=%.6Rhxs\n", pb, pb + 6));
+ }
+ else if ( pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPX_1)
+ || pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPX_2)
+ || pEthHdr->EtherType == RT_H2BE_U16(RTNET_ETHERTYPE_IPX_3))
+ {
+ LogRel((DEVICE_NAME ":IPX packet.\n"));
+ }
+ else
+ {
+ LogRel((DEVICE_NAME ":Unknown EtherType=%x D=%.6Rhxs S=%.6Rhxs\n", RT_H2BE_U16(pEthHdr->EtherType), &pEthHdr->DstMac,
+ &pEthHdr->SrcMac));
+ /* Log((DEVICE_NAME ":%.*Rhxd\n", MBLKL(pMsg), pMsg->b_rptr)); */
+ }
+}
+#endif
+
+
+/**
+ * Helper.
+ */
+DECLINLINE(bool) vboxNetFltPortSolarisIsHostMac(PVBOXNETFLTINS pThis, PCRTMAC pMac)
+{
+ return pThis->u.s.MacAddr.au16[0] == pMac->au16[0]
+ && pThis->u.s.MacAddr.au16[1] == pMac->au16[1]
+ && pThis->u.s.MacAddr.au16[2] == pMac->au16[2];
+}
+
+
+/**
+ * Receive (rx) entry point.
+ *
+ * @param pvData Private data.
+ * @param hResource The resource handle.
+ * @param pMsg The packet.
+ * @param fLoopback Whether this is a loopback packet or not.
+ */
+LOCAL void vboxNetFltSolarisRecv(void *pvData, mac_resource_handle_t hResource, mblk_t *pMsg, boolean_t fLoopback)
+{
+ Log((DEVICE_NAME ":vboxNetFltSolarisRecv pvData=%p pMsg=%p fLoopback=%d cbData=%d\n", pvData, pMsg, fLoopback,
+ pMsg ? MBLKL(pMsg) : 0));
+
+ PVBOXNETFLTINS pThis = (PVBOXNETFLTINS)pvData;
+ AssertPtrReturnVoid(pThis);
+ AssertPtrReturnVoid(pMsg);
+
+ /*
+ * Active? Retain the instance and increment the busy counter.
+ */
+ if (!vboxNetFltTryRetainBusyActive(pThis))
+ {
+ freemsgchain(pMsg);
+ return;
+ }
+
+ uint32_t fSrc = INTNETTRUNKDIR_WIRE;
+ PRTNETETHERHDR pEthHdr = (PRTNETETHERHDR)pMsg->b_rptr;
+ if ( MBLKL(pMsg) >= sizeof(RTNETETHERHDR)
+ && vboxNetFltPortSolarisIsHostMac(pThis, &pEthHdr->SrcMac))
+ fSrc = INTNETTRUNKDIR_HOST;
+
+ /*
+ * Route all received packets into the internal network.
+ */
+ uint16_t cFailed = 0;
+ for (mblk_t *pCurMsg = pMsg; pCurMsg != NULL; pCurMsg = pCurMsg->b_next)
+ {
+ unsigned cSegs = vboxNetFltSolarisMBlkCalcSGSegs(pThis, pCurMsg);
+ PINTNETSG pSG = (PINTNETSG)alloca(RT_UOFFSETOF_DYN(INTNETSG, aSegs[cSegs]));
+ int rc = vboxNetFltSolarisMBlkToSG(pThis, pMsg, pSG, cSegs, fSrc);
+ if (RT_SUCCESS(rc))
+ pThis->pSwitchPort->pfnRecv(pThis->pSwitchPort, NULL, pSG, fSrc);
+ else
+ cFailed++;
+ }
+ vboxNetFltRelease(pThis, true /* fBusy */);
+
+ if (RT_UNLIKELY(cFailed))
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG failed for %u packets.\n", cFailed));
+
+ freemsgchain(pMsg);
+
+ NOREF(hResource);
+}
+
+
+#if 0
+/**
+ * MAC layer link notification hook.
+ *
+ * @param pvArg Opaque pointer to the instance.
+ * @param Type Notification Type.
+ *
+ * @remarks This hook will be invoked for various changes to the underlying
+ * interface even when VMs aren't running so don't do any funky stuff
+ * here.
+ */
+LOCAL void vboxNetFltSolarisLinkNotify(void *pvArg, mac_notify_type_t Type)
+{
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisLinkNotify pvArg=%p Type=%d\n", pvArg, Type));
+
+ PVBOXNETFLTINS pThis = pvArg;
+ AssertPtrReturnVoid(pThis);
+ AssertPtrReturnVoid(pThis->u.s.hInterface);
+
+ switch (Type)
+ {
+ case MAC_NOTE_LINK:
+ {
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisLinkNotify link state change\n"));
+ link_state_t hLinkState = mac_stat_get(pThis->u.s.hInterface, MAC_STAT_LINK_STATE);
+ bool fDisconnectedFromHost = hLinkState == LINK_STATE_UP ? false : true;
+ if (fDisconnectedFromHost != ASMAtomicUoReadBool(&pThis->fDisconnectedFromHost))
+ {
+ ASMAtomicUoWriteBool(&pThis->fDisconnectedFromHost, fDisconnectedFromHost);
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisLinkNotify link state change: new state=%s\n",
+ fDisconnectedFromHost ? "DOWN" : "UP"));
+ }
+ break;
+ }
+
+ default:
+ return;
+ }
+}
+#endif
+
+
+/**
+ * Report capabilities and MAC address to IntNet after obtaining the MAC address
+ * of the underlying interface for a VNIC or the current interface if it's a
+ * physical/ether-stub interface.
+ *
+ * @param pThis The instance.
+ * @param hInterface The Interface handle.
+ * @param fIsVNIC Whether this interface handle corresponds to a VNIC
+ * or not.
+ *
+ * @remarks Retains the instance while doing it's job.
+ * @returns VBox status code.
+ */
+LOCAL int vboxNetFltSolarisReportInfo(PVBOXNETFLTINS pThis, mac_handle_t hInterface, bool fIsVNIC)
+{
+ mac_handle_t hLowerMac = NULL;
+ if (!fIsVNIC)
+ hLowerMac = hInterface;
+ else
+ {
+ hLowerMac = mac_get_lower_mac_handle(hInterface);
+ if (RT_UNLIKELY(!hLowerMac))
+ {
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisReportInfo failed to get lower MAC handle for '%s'\n", pThis->szName));
+ return VERR_INVALID_HANDLE;
+ }
+ }
+
+ pThis->u.s.hInterface = hLowerMac;
+
+#if 0
+ /*
+ * Try setup link notification hooks, this might fail if mac_no_notification()
+ * doesn't support it. We won't bother using the private function since link notification
+ * isn't critical for us and ignore failures.
+ */
+ pThis->u.s.hNotify = mac_notify_add(hLowerMac, vboxNetFltSolarisLinkNotify, pThis);
+ if (!pThis->u.s.hNotify)
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisReportInfo Warning! Failed to setup link notification hook.\n"));
+#endif
+
+ mac_unicast_primary_get(hLowerMac, (uint8_t *)pThis->u.s.MacAddr.au8);
+ if (vboxNetFltTryRetainBusyNotDisconnected(pThis))
+ {
+ Assert(pThis->pSwitchPort);
+ Log((DEVICE_NAME ":vboxNetFltSolarisReportInfo phys mac %.6Rhxs\n", &pThis->u.s.MacAddr));
+ pThis->pSwitchPort->pfnReportMacAddress(pThis->pSwitchPort, &pThis->u.s.MacAddr);
+ pThis->pSwitchPort->pfnReportPromiscuousMode(pThis->pSwitchPort, false); /** @todo Promisc */
+ pThis->pSwitchPort->pfnReportGsoCapabilities(pThis->pSwitchPort, 0, INTNETTRUNKDIR_WIRE | INTNETTRUNKDIR_HOST);
+ pThis->pSwitchPort->pfnReportNoPreemptDsts(pThis->pSwitchPort, 0 /* none */);
+ vboxNetFltRelease(pThis, true /*fBusy*/);
+ return VINF_SUCCESS;
+ }
+ else
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisReportInfo failed to retain interface. pThis=%p\n", pThis));
+
+ return VERR_INTNET_FLT_IF_BUSY;
+}
+
+
+/**
+ * Initialize a VNIC, optionally from a template.
+ *
+ * @param pThis The instance.
+ * @param pVNIC Pointer to the VNIC.
+ *
+ * @returns VBox status code.
+ */
+LOCAL int vboxNetFltSolarisInitVNIC(PVBOXNETFLTINS pThis, PVBOXNETFLTVNIC pVNIC)
+{
+ /*
+ * Some paranoia.
+ */
+ AssertReturn(pThis, VERR_INVALID_PARAMETER);
+ AssertReturn(pVNIC, VERR_INVALID_PARAMETER);
+ AssertReturn(pVNIC->hInterface, VERR_INVALID_POINTER);
+ AssertReturn(pVNIC->hLinkId != DATALINK_INVALID_LINKID, VERR_INVALID_HANDLE);
+ AssertReturn(!pVNIC->hClient, VERR_INVALID_POINTER);
+
+ int rc = mac_client_open(pVNIC->hInterface, &pVNIC->hClient,
+ NULL, /* name of this client */
+ MAC_OPEN_FLAGS_USE_DATALINK_NAME | /* client name same as underlying NIC */
+ MAC_OPEN_FLAGS_MULTI_PRIMARY /* allow multiple primary unicasts */
+ );
+ if (RT_LIKELY(!rc))
+ {
+ if (pVNIC->pVNICTemplate)
+ rc = mac_client_set_resources(pVNIC->hClient, &pVNIC->pVNICTemplate->Resources);
+
+ if (RT_LIKELY(!rc))
+ {
+ Log((DEVICE_NAME ":vboxNetFltSolarisInitVNIC succesfully initialized VNIC.\n"));
+ return VINF_SUCCESS;
+ }
+ else
+ {
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisInitVNIC mac_client_set_resources failed. rc=%d\n", rc));
+ rc = VERR_INTNET_FLT_VNIC_INIT_FAILED;
+ }
+
+ mac_client_close(pVNIC->hClient, 0 /* flags */);
+ pVNIC->hClient = NULL;
+ }
+ else
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisInitVNIC failed to open mac client for '%s' rc=%d\n", pThis->szName, rc));
+
+ return VERR_INTNET_FLT_VNIC_OPEN_FAILED;
+}
+
+
+
+/**
+ * Get the underlying link name for a VNIC (template).
+ *
+ * @return VBox status code.
+ * @param hVNICMacHandle The handle to the VNIC.
+ * @param pszLowerLinkName Where to store the lower-mac linkname, must be
+ * at least MAXLINKNAMELEN in size.
+ */
+LOCAL int vboxNetFltSolarisGetLowerLinkName(mac_handle_t hVNICMacHandle, char *pszLowerLinkName)
+{
+ Assert(mac_is_vnic(hVNICMacHandle));
+ mac_handle_t hPhysLinkHandle = mac_get_lower_mac_handle(hVNICMacHandle);
+ if (RT_LIKELY(hPhysLinkHandle))
+ {
+ datalink_id_t PhysLinkId;
+ const char *pszMacName = mac_name(hPhysLinkHandle);
+ int rc = vboxNetFltSolarisGetLinkId(pszMacName, &PhysLinkId);
+ if (RT_SUCCESS(rc))
+ {
+ rc = dls_mgmt_get_linkinfo(PhysLinkId, pszLowerLinkName, NULL /*class*/, NULL /*media*/, NULL /*flags*/);
+ if (RT_LIKELY(!rc))
+ return VINF_SUCCESS;
+
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisGetLowerLinkName failed to get link info. pszMacName=%s pszLowerLinkName=%s\n",
+ pszMacName, pszLowerLinkName));
+ return VERR_INTNET_FLT_LOWER_LINK_INFO_NOT_FOUND;
+ }
+
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisGetLowerLinkName failed to get link id. pszMacName=%s pszLowerLinkName=%s\n",
+ pszMacName, pszLowerLinkName));
+ return VERR_INTNET_FLT_LOWER_LINK_ID_NOT_FOUND;
+ }
+
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisGetLowerLinkName failed to get lower-mac. pszLowerLinkName=%s\n", pszLowerLinkName));
+ return VERR_INTNET_FLT_LOWER_LINK_OPEN_FAILED;
+}
+
+
+/**
+ * Initializes the VNIC template. This involves opening the template VNIC to
+ * retreive info. like the VLAN Id, underlying MAC address etc.
+ *
+ * @param pThis The VM connection instance.
+ * @param pVNICTemplate Pointer to a VNIC template to initialize.
+ *
+ * @returns VBox status code.
+ */
+LOCAL int vboxNetFltSolarisInitVNICTemplate(PVBOXNETFLTINS pThis, PVBOXNETFLTVNICTEMPLATE pVNICTemplate)
+{
+ Log((DEVICE_NAME ":vboxNetFltSolarisInitVNICTemplate pThis=%p pVNICTemplate=%p\n", pThis, pVNICTemplate));
+
+ AssertReturn(pVNICTemplate, VERR_INVALID_PARAMETER);
+ AssertReturn(pThis->u.s.fIsVNICTemplate == true, VERR_INVALID_STATE);
+
+ /*
+ * Get the VNIC template's datalink ID.
+ */
+ datalink_id_t VNICLinkId;
+ int rc = vboxNetFltSolarisGetLinkId(pThis->szName, &VNICLinkId);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Open the VNIC to obtain a MAC handle so as to retreive the VLAN ID.
+ */
+ mac_handle_t hInterface;
+ rc = mac_open_by_linkid(VNICLinkId, &hInterface);
+ if (!rc)
+ {
+ /*
+ * Get the underlying linkname.
+ */
+ AssertCompile(sizeof(pVNICTemplate->szLinkName) >= MAXLINKNAMELEN);
+ rc = vboxNetFltSolarisGetLowerLinkName(hInterface, pVNICTemplate->szLinkName);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Now open the VNIC template to retrieve the VLAN Id & resources.
+ */
+ mac_client_handle_t hClient;
+ rc = mac_client_open(hInterface, &hClient,
+ NULL, /* name of this client */
+ MAC_OPEN_FLAGS_USE_DATALINK_NAME | /* client name same as underlying NIC */
+ MAC_OPEN_FLAGS_MULTI_PRIMARY /* allow multiple primary unicasts */
+ );
+ if (RT_LIKELY(!rc))
+ {
+ pVNICTemplate->uVLANId = mac_client_vid(hClient);
+ mac_client_get_resources(hClient, &pVNICTemplate->Resources);
+ mac_client_close(hClient, 0 /* fFlags */);
+ mac_close(hInterface);
+
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisInitVNICTemplate successfully init. VNIC template. szLinkName=%s "
+ "VLAN Id=%u\n", pVNICTemplate->szLinkName, pVNICTemplate->uVLANId));
+ return VINF_SUCCESS;
+ }
+ else
+ {
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisInitVNICTemplate failed to open VNIC template. rc=%d\n", rc));
+ rc = VERR_INTNET_FLT_IF_FAILED;
+ }
+ }
+ else
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisInitVNICTemplate failed to get lower linkname for VNIC template '%s'.\n",
+ pThis->szName));
+
+ mac_close(hInterface);
+ }
+ else
+ {
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisInitVNICTemplate failed to open by link ID. rc=%d\n", rc));
+ rc = VERR_INTNET_FLT_IF_FAILED;
+ }
+ }
+ else
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisInitVNICTemplate failed to get VNIC template link Id. rc=%d\n", rc));
+
+ return rc;
+}
+
+
+/**
+ * Allocate a VNIC structure.
+ *
+ * @returns An allocated VNIC structure or NULL in case of errors.
+ */
+LOCAL PVBOXNETFLTVNIC vboxNetFltSolarisAllocVNIC(void)
+{
+ PVBOXNETFLTVNIC pVNIC = RTMemAllocZ(sizeof(VBOXNETFLTVNIC));
+ if (RT_UNLIKELY(!pVNIC))
+ return NULL;
+
+ pVNIC->u32Magic = VBOXNETFLTVNIC_MAGIC;
+ pVNIC->fCreated = false;
+ pVNIC->pVNICTemplate = NULL;
+ pVNIC->pvIf = NULL;
+ pVNIC->hInterface = NULL;
+ pVNIC->hLinkId = DATALINK_INVALID_LINKID;
+ pVNIC->hClient = NULL;
+ pVNIC->hUnicast = NULL;
+ pVNIC->hPromisc = NULL;
+ RT_ZERO(pVNIC->szName);
+ list_link_init(&pVNIC->hNode);
+ return pVNIC;
+}
+
+
+/**
+ * Frees an allocated VNIC.
+ *
+ * @param pVNIC Pointer to the VNIC.
+ */
+DECLINLINE(void) vboxNetFltSolarisFreeVNIC(PVBOXNETFLTVNIC pVNIC)
+{
+ RTMemFree(pVNIC);
+}
+
+
+/**
+ * Destroy a created VNIC if it was created by us, or just
+ * de-initializes the VNIC freeing up resources handles.
+ *
+ * @param pVNIC Pointer to the VNIC.
+ */
+LOCAL void vboxNetFltSolarisDestroyVNIC(PVBOXNETFLTVNIC pVNIC)
+{
+ AssertPtrReturnVoid(pVNIC);
+ AssertMsgReturnVoid(pVNIC->u32Magic == VBOXNETFLTVNIC_MAGIC, ("pVNIC=%p u32Magic=%#x\n", pVNIC, pVNIC->u32Magic));
+ if (pVNIC)
+ {
+ if (pVNIC->hClient)
+ {
+#if 0
+ if (pVNIC->hUnicast)
+ {
+ mac_unicast_remove(pVNIC->hClient, pVNIC->hUnicast);
+ pVNIC->hUnicast = NULL;
+ }
+#endif
+
+ if (pVNIC->hPromisc)
+ {
+ mac_promisc_remove(pVNIC->hPromisc);
+ pVNIC->hPromisc = NULL;
+ }
+
+ mac_rx_clear(pVNIC->hClient);
+
+ mac_client_close(pVNIC->hClient, 0 /* fFlags */);
+ pVNIC->hClient = NULL;
+ }
+
+ if (pVNIC->hInterface)
+ {
+ mac_close(pVNIC->hInterface);
+ pVNIC->hInterface = NULL;
+ }
+
+ if (pVNIC->fCreated)
+ {
+ vnic_delete(pVNIC->hLinkId, 0 /* Flags */);
+ pVNIC->hLinkId = DATALINK_INVALID_LINKID;
+ pVNIC->fCreated = false;
+ }
+
+ if (pVNIC->pVNICTemplate)
+ {
+ RTMemFree(pVNIC->pVNICTemplate);
+ pVNIC->pVNICTemplate = NULL;
+ }
+ }
+}
+
+
+/**
+ * Create a non-persistent VNIC over the given interface.
+ *
+ * @param pThis The VM connection instance.
+ * @param ppVNIC Where to store the created VNIC.
+ *
+ * @returns VBox status code.
+ */
+LOCAL int vboxNetFltSolarisCreateVNIC(PVBOXNETFLTINS pThis, PVBOXNETFLTVNIC *ppVNIC)
+{
+ Log((DEVICE_NAME ":vboxNetFltSolarisCreateVNIC pThis=%p\n", pThis));
+
+ AssertReturn(pThis, VERR_INVALID_POINTER);
+ AssertReturn(ppVNIC, VERR_INVALID_POINTER);
+
+ int rc = VERR_INVALID_STATE;
+ PVBOXNETFLTVNIC pVNIC = vboxNetFltSolarisAllocVNIC();
+ if (RT_UNLIKELY(!pVNIC))
+ return VERR_NO_MEMORY;
+
+ /*
+ * Set a random MAC address for now. It will be changed to the VM interface's
+ * MAC address later, see vboxNetFltPortOsNotifyMacAddress().
+ */
+ RTMAC GuestMac;
+ GuestMac.au8[0] = 0x08;
+ GuestMac.au8[1] = 0x00;
+ GuestMac.au8[2] = 0x27;
+ RTRandBytes(&GuestMac.au8[3], 3);
+
+ AssertCompile(sizeof(RTMAC) <= MAXMACADDRLEN);
+
+ const char *pszLinkName = pThis->szName;
+ uint16_t uVLANId = VLAN_ID_NONE;
+ vnic_mac_addr_type_t AddrType = VNIC_MAC_ADDR_TYPE_FIXED;
+ vnic_ioc_diag_t Diag = VNIC_IOC_DIAG_NONE;
+ int MacSlot = 0;
+ int MacLen = sizeof(GuestMac);
+ uint32_t fFlags = 0;
+
+ if (pThis->u.s.fIsVNICTemplate)
+ {
+ pVNIC->pVNICTemplate = RTMemAllocZ(sizeof(VBOXNETFLTVNICTEMPLATE));
+ if (RT_UNLIKELY(!pVNIC->pVNICTemplate))
+ {
+ vboxNetFltSolarisFreeVNIC(pVNIC);
+ return VERR_NO_MEMORY;
+ }
+
+ /*
+ * Initialize the VNIC template.
+ */
+ rc = vboxNetFltSolarisInitVNICTemplate(pThis, pVNIC->pVNICTemplate);
+ if (RT_FAILURE(rc))
+ {
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisCreateVNIC failed to initialize VNIC from VNIC template. rc=%Rrc\n", rc));
+ vboxNetFltSolarisFreeVNIC(pVNIC);
+ return rc;
+ }
+
+ pszLinkName = pVNIC->pVNICTemplate->szLinkName;
+ uVLANId = pVNIC->pVNICTemplate->uVLANId;
+#if 0
+ /*
+ * Required only if we're creating a VLAN interface & not a VNIC with a VLAN Id.
+ */
+ if (uVLANId != VLAN_ID_NONE)
+ fFlags |= MAC_VLAN;
+#endif
+ Log((DEVICE_NAME ":vboxNetFltSolarisCreateVNIC pThis=%p VLAN Id=%u\n", pThis, uVLANId));
+ }
+
+ /*
+ * Make sure the dynamic VNIC we're creating doesn't already exists, if so pick a new instance.
+ * This is to avoid conflicts with users manually creating VNICs whose name starts with VBOXBOW_VNIC_NAME.
+ */
+ do
+ {
+ AssertCompile(sizeof(pVNIC->szName) > sizeof(VBOXBOW_VNIC_NAME "18446744073709551615" /* UINT64_MAX */));
+ RTStrPrintf(pVNIC->szName, sizeof(pVNIC->szName), "%s%RU64", VBOXBOW_VNIC_NAME, g_VBoxNetFltSolarisVNICId);
+ mac_handle_t hTmpMacHandle;
+ rc = mac_open_by_linkname(pVNIC->szName, &hTmpMacHandle);
+ if (rc)
+ break;
+ mac_close(hTmpMacHandle);
+ ASMAtomicIncU64(&g_VBoxNetFltSolarisVNICId);
+ } while (1);
+
+ /*
+ * Create the VNIC under 'pszLinkName', which can be the one from the VNIC template or can
+ * be a physical interface.
+ */
+ rc = vnic_create(pVNIC->szName, pszLinkName, &AddrType, &MacLen, GuestMac.au8, &MacSlot, 0 /* Mac-Prefix Length */, uVLANId,
+ fFlags, &pVNIC->hLinkId, &Diag, NULL /* Reserved */);
+ if (!rc)
+ {
+ pVNIC->fCreated = true;
+ ASMAtomicIncU64(&g_VBoxNetFltSolarisVNICId);
+
+ /*
+ * Now try opening the created VNIC.
+ */
+ rc = mac_open_by_linkid(pVNIC->hLinkId, &pVNIC->hInterface);
+ if (!rc)
+ {
+ /*
+ * Initialize the VNIC from the physical interface or the VNIC template.
+ */
+ rc = vboxNetFltSolarisInitVNIC(pThis, pVNIC);
+ if (RT_SUCCESS(rc))
+ {
+ Log((DEVICE_NAME ":vboxNetFltSolarisCreateVNIC created VNIC '%s' over '%s' with random mac %.6Rhxs\n",
+ pVNIC->szName, pszLinkName, &GuestMac));
+ *ppVNIC = pVNIC;
+ return VINF_SUCCESS;
+ }
+
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisCreateVNIC vboxNetFltSolarisInitVNIC failed. rc=%d\n", rc));
+ mac_close(pVNIC->hInterface);
+ pVNIC->hInterface = NULL;
+ }
+ else
+ {
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisCreateVNIC logrel failed to open VNIC '%s' over '%s'. rc=%d\n", pVNIC->szName,
+ pThis->szName, rc));
+ rc = VERR_INTNET_FLT_VNIC_LINK_ID_NOT_FOUND;
+ }
+
+ vboxNetFltSolarisDestroyVNIC(pVNIC);
+ }
+ else
+ {
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisCreateVNIC failed to create VNIC '%s' over '%s' rc=%d Diag=%d\n", pVNIC->szName,
+ pszLinkName, rc, Diag));
+ rc = VERR_INTNET_FLT_VNIC_CREATE_FAILED;
+ }
+
+ vboxNetFltSolarisFreeVNIC(pVNIC);
+
+ return rc;
+}
+
+
+/**
+ * Wrapper for getting the datalink ID given the MAC name.
+ *
+ * @param pszMacName The MAC name.
+ * @param pLinkId Where to store the datalink ID.
+ *
+ * @returns VBox status code.
+ */
+DECLINLINE(int) vboxNetFltSolarisGetLinkId(const char *pszMacName, datalink_id_t *pLinkId)
+{
+ /*
+ * dls_mgmt_get_linkid() requires to be in a state to answer upcalls. We should always use this
+ * first before resorting to other means to retrieve the MAC name.
+ */
+ int rc = dls_mgmt_get_linkid(pszMacName, pLinkId);
+ if (rc)
+ rc = dls_devnet_macname2linkid(pszMacName, pLinkId);
+
+ if (RT_LIKELY(!rc))
+ return VINF_SUCCESS;
+
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisGetLinkId failed for '%s'. rc=%d\n", pszMacName, rc));
+ return RTErrConvertFromErrno(rc);
+}
+
+
+/**
+ * Set the promiscuous mode RX hook.
+ *
+ * @param pThis The VM connection instance.
+ * @param pVNIC Pointer to the VNIC.
+ *
+ * @returns VBox status code.
+ */
+DECLINLINE(int) vboxNetFltSolarisSetPromisc(PVBOXNETFLTINS pThis, PVBOXNETFLTVNIC pVNIC)
+{
+ int rc = VINF_SUCCESS;
+ if (!pVNIC->hPromisc)
+ {
+ rc = mac_promisc_add(pVNIC->hClient, MAC_CLIENT_PROMISC_FILTERED, vboxNetFltSolarisRecv, pThis, &pVNIC->hPromisc,
+ MAC_PROMISC_FLAGS_NO_TX_LOOP | MAC_PROMISC_FLAGS_VLAN_TAG_STRIP | MAC_PROMISC_FLAGS_NO_PHYS);
+ if (RT_UNLIKELY(rc))
+ LogRel((DEVICE_NAME ":vboxNetFltSolarisSetPromisc failed. rc=%d\n", rc));
+ rc = RTErrConvertFromErrno(rc);
+ }
+ return rc;
+}
+
+
+/**
+ * Clear the promiscuous mode RX hook.
+ *
+ * @param pThis The VM connection instance.
+ * @param pVNIC Pointer to the VNIC.
+ */
+DECLINLINE(void) vboxNetFltSolarisRemovePromisc(PVBOXNETFLTINS pThis, PVBOXNETFLTVNIC pVNIC)
+{
+ if (pVNIC->hPromisc)
+ {
+ mac_promisc_remove(pVNIC->hPromisc);
+ pVNIC->hPromisc = NULL;
+ }
+}
+
+
+/* -=-=-=-=-=- Common Hooks -=-=-=-=-=- */
+
+
+void vboxNetFltPortOsSetActive(PVBOXNETFLTINS pThis, bool fActive)
+{
+ Log((DEVICE_NAME ":vboxNetFltPortOsSetActive pThis=%p fActive=%d\n", pThis, fActive));
+
+ /*
+ * Reactivate/quiesce the interface.
+ */
+ PVBOXNETFLTVNIC pVNIC = list_head(&pThis->u.s.hVNICs);
+ if (fActive)
+ {
+ for (; pVNIC != NULL; pVNIC = list_next(&pThis->u.s.hVNICs, pVNIC))
+ if (pVNIC->hClient)
+ {
+#if 0
+ mac_rx_set(pVNIC->hClient, vboxNetFltSolarisRecv, pThis);
+#endif
+ vboxNetFltSolarisSetPromisc(pThis, pVNIC);
+ }
+ }
+ else
+ {
+ for (; pVNIC != NULL; pVNIC = list_next(&pThis->u.s.hVNICs, pVNIC))
+ if (pVNIC->hClient)
+ {
+#if 0
+ mac_rx_clear(pVNIC->hClient);
+#endif
+ vboxNetFltSolarisRemovePromisc(pThis, pVNIC);
+ }
+ }
+}
+
+
+int vboxNetFltOsDisconnectIt(PVBOXNETFLTINS pThis)
+{
+ Log((DEVICE_NAME ":vboxNetFltOsDisconnectIt pThis=%p\n", pThis));
+ return VINF_SUCCESS;
+}
+
+
+int vboxNetFltOsConnectIt(PVBOXNETFLTINS pThis)
+{
+ Log((DEVICE_NAME ":vboxNetFltOsConnectIt pThis=%p\n", pThis));
+ return VINF_SUCCESS;
+}
+
+
+void vboxNetFltOsDeleteInstance(PVBOXNETFLTINS pThis)
+{
+ Log((DEVICE_NAME ":vboxNetFltOsDeleteInstance pThis=%p\n", pThis));
+
+ if (pThis->u.s.hNotify)
+ mac_notify_remove(pThis->u.s.hNotify, B_TRUE /* Wait */);
+
+ /*
+ * Destroy all managed VNICs. If a VNIC was passed to us, there
+ * will be only 1 item in the list, otherwise as many interfaces
+ * that were somehow not destroyed using DisconnectInterface() will be
+ * present.
+ */
+ PVBOXNETFLTVNIC pVNIC = NULL;
+ while ((pVNIC = list_remove_head(&pThis->u.s.hVNICs)) != NULL)
+ {
+ vboxNetFltSolarisDestroyVNIC(pVNIC);
+ vboxNetFltSolarisFreeVNIC(pVNIC);
+ }
+
+ list_destroy(&pThis->u.s.hVNICs);
+}
+
+
+int vboxNetFltOsInitInstance(PVBOXNETFLTINS pThis, void *pvContext)
+{
+ Log((DEVICE_NAME ":vboxNetFltOsInitInstance pThis=%p pvContext=%p\n", pThis, pvContext));
+
+ /*
+ * Figure out if the interface is a VNIC or a physical/etherstub/whatever NIC, then
+ * do the actual VNIC creation if necessary in vboxNetFltPortOsConnectInterface().
+ */
+ mac_handle_t hInterface;
+ int rc = mac_open_by_linkname(pThis->szName, &hInterface);
+ if (RT_LIKELY(!rc))
+ {
+ rc = mac_is_vnic(hInterface);
+ if (!rc)
+ {
+ Log((DEVICE_NAME ":vboxNetFltOsInitInstance pThis=%p physical interface '%s' detected.\n", pThis, pThis->szName));
+ pThis->u.s.fIsVNIC = false;
+ }
+ else
+ {
+ pThis->u.s.fIsVNIC = true;
+ if (RTStrNCmp(pThis->szName, VBOXBOW_VNIC_TEMPLATE_NAME, sizeof(VBOXBOW_VNIC_TEMPLATE_NAME) - 1) == 0)
+ {
+ Log((DEVICE_NAME ":vboxNetFltOsInitInstance pThis=%p VNIC template '%s' detected.\n", pThis, pThis->szName));
+ pThis->u.s.fIsVNICTemplate = true;
+ }
+ }
+
+ if ( pThis->u.s.fIsVNIC
+ && !pThis->u.s.fIsVNICTemplate)
+ Log((DEVICE_NAME ":vboxNetFltOsInitInstance pThis=%p VNIC '%s' detected.\n", pThis, pThis->szName));
+
+ /*
+ * Report info. (host MAC address, promiscuous, GSO capabilities etc.) to IntNet.
+ */
+ rc = vboxNetFltSolarisReportInfo(pThis, hInterface, pThis->u.s.fIsVNIC);
+ if (RT_FAILURE(rc))
+ LogRel((DEVICE_NAME ":vboxNetFltOsInitInstance failed to report info. rc=%d\n", rc));
+
+ mac_close(hInterface);
+ }
+ else
+ {
+ LogRel((DEVICE_NAME ":vboxNetFltOsInitInstance failed to open link '%s'! rc=%d\n", pThis->szName, rc));
+ rc = VERR_INTNET_FLT_IF_FAILED;
+ }
+
+ return rc;
+}
+
+
+int vboxNetFltOsPreInitInstance(PVBOXNETFLTINS pThis)
+{
+ /*
+ * Init. the solaris specific data.
+ */
+ pThis->u.s.fIsVNIC = false;
+ pThis->u.s.fIsVNICTemplate = false;
+ list_create(&pThis->u.s.hVNICs, sizeof(VBOXNETFLTVNIC), offsetof(VBOXNETFLTVNIC, hNode));
+ pThis->u.s.hNotify = NULL;
+ RT_ZERO(pThis->u.s.MacAddr);
+ return VINF_SUCCESS;
+}
+
+
+bool vboxNetFltOsMaybeRediscovered(PVBOXNETFLTINS pThis)
+{
+ /*
+ * @todo Think about this.
+ */
+ return false;
+}
+
+
+int vboxNetFltPortOsXmit(PVBOXNETFLTINS pThis, void *pvIfData, PINTNETSG pSG, uint32_t fDst)
+{
+ /*
+ * Validate parameters.
+ */
+ PVBOXNETFLTVNIC pVNIC = pvIfData;
+ AssertPtrReturn(pVNIC, VERR_INVALID_POINTER);
+ AssertMsgReturn(pVNIC->u32Magic == VBOXNETFLTVNIC_MAGIC,
+ ("Invalid magic=%#x (expected %#x)\n", pVNIC->u32Magic, VBOXNETFLTVNIC_MAGIC),
+ VERR_INVALID_MAGIC);
+
+ /*
+ * Xmit the packet down the appropriate VNIC interface.
+ */
+ int rc = VINF_SUCCESS;
+ mblk_t *pMsg = vboxNetFltSolarisMBlkFromSG(pThis, pSG, fDst);
+ if (RT_LIKELY(pMsg))
+ {
+ Log((DEVICE_NAME ":vboxNetFltPortOsXmit pThis=%p cbData=%d\n", pThis, MBLKL(pMsg)));
+
+ mac_tx_cookie_t pXmitCookie = mac_tx(pVNIC->hClient, pMsg, 0 /* Hint */, MAC_DROP_ON_NO_DESC, NULL /* return message */);
+ if (RT_LIKELY(!pXmitCookie))
+ return VINF_SUCCESS;
+
+ pMsg = NULL;
+ rc = VERR_NET_IO_ERROR;
+ LogRel((DEVICE_NAME ":vboxNetFltPortOsXmit Xmit failed pVNIC=%p.\n", pVNIC));
+ }
+ else
+ {
+ LogRel((DEVICE_NAME ":vboxNetFltPortOsXmit no memory for allocating Xmit packet.\n"));
+ rc = VERR_NO_MEMORY;
+ }
+
+ return rc;
+}
+
+
+void vboxNetFltPortOsNotifyMacAddress(PVBOXNETFLTINS pThis, void *pvIfData, PCRTMAC pMac)
+{
+ Log((DEVICE_NAME ":vboxNetFltPortOSNotifyMacAddress pszIf=%s pszVNIC=%s MAC=%.6Rhxs\n", pThis->szName,
+ ((PVBOXNETFLTVNIC)pvIfData)->szName, pMac));
+
+ /*
+ * Validate parameters.
+ */
+ PVBOXNETFLTVNIC pVNIC = pvIfData;
+ AssertPtrReturnVoid(pVNIC);
+ AssertMsgReturnVoid(pVNIC->u32Magic == VBOXNETFLTVNIC_MAGIC,
+ ("Invalid pVNIC=%p magic=%#x (expected %#x)\n", pvIfData, pVNIC->u32Magic, VBOXNETFLTVNIC_MAGIC));
+ AssertMsgReturnVoid(pVNIC->hLinkId != DATALINK_INVALID_LINKID,
+ ("Invalid hLinkId pVNIC=%p magic=%#x\n", pVNIC, pVNIC->u32Magic));
+
+ /*
+ * Set the MAC address of the VNIC to the one used by the VM interface.
+ */
+ uchar_t au8GuestMac[MAXMACADDRLEN];
+ bcopy(pMac->au8, au8GuestMac, sizeof(RTMAC));
+
+ vnic_mac_addr_type_t AddrType = VNIC_MAC_ADDR_TYPE_FIXED;
+ vnic_ioc_diag_t Diag = VNIC_IOC_DIAG_NONE;
+ int MacSlot = 0;
+ int MacLen = sizeof(RTMAC);
+
+ int rc = vnic_modify_addr(pVNIC->hLinkId, &AddrType, &MacLen, au8GuestMac, &MacSlot, 0 /* Mac-Prefix Length */, &Diag);
+ if (RT_LIKELY(!rc))
+ {
+ /*
+ * Remove existing unicast address, promisc. and the RX hook.
+ */
+#if 0
+ if (pVNIC->hUnicast)
+ {
+ mac_rx_clear(pVNIC->hClient);
+ mac_unicast_remove(pVNIC->hClient, pVNIC->hUnicast);
+ pVNIC->hUnicast = NULL;
+ }
+#endif
+
+ if (pVNIC->hPromisc)
+ {
+ mac_promisc_remove(pVNIC->hPromisc);
+ pVNIC->hPromisc = NULL;
+ }
+
+ mac_diag_t MacDiag = MAC_DIAG_NONE;
+ /* uint16_t uVLANId = pVNIC->pVNICTemplate ? pVNIC->pVNICTemplate->uVLANId : 0; */
+#if 0
+ rc = mac_unicast_add(pVNIC->hClient, NULL, MAC_UNICAST_PRIMARY, &pVNIC->hUnicast, 0 /* VLAN Id */, &MacDiag);
+#endif
+ if (RT_LIKELY(!rc))
+ {
+ rc = vboxNetFltSolarisSetPromisc(pThis, pVNIC);
+#if 0
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Set the RX receive function.
+ * This shouldn't be necessary as vboxNetFltPortOsSetActive() will be invoked after this, but in the future,
+ * if the guest NIC changes MAC address this may not be followed by a vboxNetFltPortOsSetActive() call,
+ * so set it here anyway.
+ */
+ mac_rx_set(pVNIC->hClient, vboxNetFltSolarisRecv, pThis);
+ Log((DEVICE_NAME ":vboxNetFltPortOsNotifyMacAddress successfully added unicast address %.6Rhxs\n", pMac));
+ }
+ else
+ LogRel((DEVICE_NAME ":vboxNetFltPortOsNotifyMacAddress failed to set promiscuous mode. rc=%d\n", rc));
+ mac_unicast_remove(pVNIC->hClient, pVNIC->hUnicast);
+ pVNIC->hUnicast = NULL;
+#endif
+ }
+ else
+ {
+ LogRel((DEVICE_NAME ":vboxNetFltPortOsNotifyMacAddress failed to add primary unicast address. rc=%d Diag=%d\n", rc,
+ MacDiag));
+ }
+ }
+ else
+ {
+ /*
+ * They really ought to use EEXIST, but I'm afraid this error comes from the VNIC device driver directly.
+ * Sequence: vnic_modify_addr()->mac_unicast_primary_set()->mac_update_macaddr() which uses a function pointer
+ * to the MAC driver (calls mac_vnic_unicast_set() in our case). Documented here if the error code should change we know
+ * where to look.
+ */
+ if (rc == ENOTSUP)
+ {
+ LogRel((DEVICE_NAME ":vboxNetFltPortOsNotifyMacAddress: failed! a VNIC with mac %.6Rhxs probably already exists.",
+ pMac, rc));
+ LogRel((DEVICE_NAME ":vboxNetFltPortOsNotifyMacAddress: This NIC cannot establish connection. szName=%s szVNIC=%s\n",
+ pThis->szName, pVNIC->szName));
+ }
+ else
+ LogRel((DEVICE_NAME ":vboxNetFltPortOsNotifyMacAddress failed! mac %.6Rhxs rc=%d Diag=%d\n", pMac, rc, Diag));
+ }
+}
+
+
+int vboxNetFltPortOsConnectInterface(PVBOXNETFLTINS pThis, void *pvIf, void **ppvIfData)
+{
+ Log((DEVICE_NAME ":vboxNetFltPortOsConnectInterface pThis=%p pvIf=%p\n", pThis, pvIf));
+
+ int rc = VINF_SUCCESS;
+
+ /*
+ * If the underlying interface is a physical interface or a VNIC template, we need to create
+ * a VNIC per guest NIC.
+ */
+ if ( !pThis->u.s.fIsVNIC
+ || pThis->u.s.fIsVNICTemplate)
+ {
+ PVBOXNETFLTVNIC pVNIC = NULL;
+ rc = vboxNetFltSolarisCreateVNIC(pThis, &pVNIC);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * VM Interface<->VNIC association so that we can Xmit/Recv on the right ones.
+ */
+ pVNIC->pvIf = pvIf;
+ *ppvIfData = pVNIC;
+
+ /*
+ * Add the created VNIC to the list of VNICs we manage.
+ */
+ list_insert_tail(&pThis->u.s.hVNICs, pVNIC);
+ return VINF_SUCCESS;
+ }
+ else
+ LogRel((DEVICE_NAME ":vboxNetFltPortOsConnectInterface failed to create VNIC rc=%d\n", rc));
+ }
+ else
+ {
+ /*
+ * This is a VNIC passed to us, use it directly.
+ */
+ PVBOXNETFLTVNIC pVNIC = vboxNetFltSolarisAllocVNIC();
+ if (RT_LIKELY(pVNIC))
+ {
+ pVNIC->fCreated = false;
+
+ rc = mac_open_by_linkname(pThis->szName, &pVNIC->hInterface);
+ if (!rc)
+ {
+ /*
+ * Obtain the data link ID for this VNIC, it's needed for modifying the MAC address among other things.
+ */
+ rc = vboxNetFltSolarisGetLinkId(pThis->szName, &pVNIC->hLinkId);
+ if (RT_SUCCESS(rc))
+ {
+ /*
+ * Initialize the VNIC and add it to the list of managed VNICs.
+ */
+ RTStrPrintf(pVNIC->szName, sizeof(pVNIC->szName), "%s", pThis->szName);
+ rc = vboxNetFltSolarisInitVNIC(pThis, pVNIC);
+ if (!rc)
+ {
+ pVNIC->pvIf = pvIf;
+ *ppvIfData = pVNIC;
+ list_insert_head(&pThis->u.s.hVNICs, pVNIC);
+ return VINF_SUCCESS;
+ }
+ else
+ LogRel((DEVICE_NAME ":vboxNetFltPortOsConnectInterface failed to initialize VNIC. rc=%d\n", rc));
+ }
+ else
+ {
+ LogRel((DEVICE_NAME ":vboxNetFltPortOsConnectInterface failed to get link id for '%s'. rc=%d\n",
+ pThis->szName, rc));
+ }
+ }
+ else
+ {
+ LogRel((DEVICE_NAME ":vboxNetFltPortOsConnectInterface failed to open VNIC '%s'. rc=%d\n", pThis->szName, rc));
+ rc = VERR_OPEN_FAILED;
+ }
+
+ vboxNetFltSolarisFreeVNIC(pVNIC);
+ }
+ else
+ {
+ LogRel((DEVICE_NAME ":vboxNetFltOsInitInstance failed to allocate VNIC private data.\n"));
+ rc = VERR_NO_MEMORY;
+ }
+ }
+
+ return rc;
+}
+
+
+int vboxNetFltPortOsDisconnectInterface(PVBOXNETFLTINS pThis, void *pvIfData)
+{
+ Log((DEVICE_NAME ":vboxNetFltPortOsDisconnectInterface pThis=%p\n", pThis));
+
+ /*
+ * It is possible we get called when vboxNetFltPortOsConnectInterface() didn't succeed
+ * in which case pvIfData will be NULL. See intnetR0NetworkCreateIf() pfnConnectInterface call
+ * through reference counting in SUPR0ObjRelease() for the "pIf" object.
+ */
+ PVBOXNETFLTVNIC pVNIC = pvIfData;
+ if (RT_LIKELY(pVNIC))
+ {
+ AssertMsgReturn(pVNIC->u32Magic == VBOXNETFLTVNIC_MAGIC,
+ ("Invalid magic=%#x (expected %#x)\n", pVNIC->u32Magic, VBOXNETFLTVNIC_MAGIC), VERR_INVALID_POINTER);
+
+ /*
+ * If the underlying interface is a physical interface or a VNIC template, we need to delete the created VNIC.
+ */
+ if ( !pThis->u.s.fIsVNIC
+ || pThis->u.s.fIsVNICTemplate)
+ {
+ /*
+ * Remove the VNIC from the list, destroy and free it.
+ */
+ list_remove(&pThis->u.s.hVNICs, pVNIC);
+ Log((DEVICE_NAME ":vboxNetFltPortOsDisconnectInterface destroying pVNIC=%p\n", pVNIC));
+ vboxNetFltSolarisDestroyVNIC(pVNIC);
+ vboxNetFltSolarisFreeVNIC(pVNIC);
+ }
+ }
+
+ return VINF_SUCCESS;
+}
+