VBoxNetFltBow-solaris.c revision 9b8b7c614b03dfc2a0d6fc2bea4c3cfdf563879a
/* $Id$ */
/** @file
* VBoxNetFlt - Network Filter Driver (Host), Solaris Specific Code.
*/
/*
* Copyright (C) 2008 Oracle Corporation
*
* This file is part of VirtualBox Open Source Edition (OSE), as
* available from http://www.virtualbox.org. This file is free software;
* 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_NET_FLT_DRV
#include <VBox/intnetinline.h>
#include <iprt/initterm.h>
#include <iprt/spinlock.h>
#include <sys/dls_mgmt.h>
#include <sys/vnic_mgmt.h>
#include <sys/mac_client.h>
#include <sys/mac_provider.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
#if defined(DEBUG_ramshankar)
# define LOCAL
#endif
/** VLAN tag masking, should probably be in IPRT? */
typedef struct VLANHEADER
{
} VLANHEADER;
typedef struct VLANHEADER *PVLANHEADER;
#ifndef VLAN_ID_NONE
# define VLAN_ID_NONE 0
#endif
#ifndef MAXLINKNAMESPECIFIER
#endif
/* Private: from sys/mac_client_priv.h, mac client function prototypes. */
extern void mac_client_get_resources(mac_client_handle_t hClient, mac_resource_props_t *pResources);
/*******************************************************************************
* Kernel Entry Hooks *
*******************************************************************************/
LOCAL int VBoxNetFltSolarisGetInfo(dev_info_t *pDip, ddi_info_cmd_t enmCmd, void *pArg, void **ppResult);
/*******************************************************************************
* Structures and Typedefs *
*******************************************************************************/
/**
*/
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 */
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 */
nulldev, /* identify */
nulldev, /* probe */
nodev, /* reset */
NULL, /* bus ops */
nodev, /* power */
};
/**
* modldrv: export driver specifics to the kernel
*/
static struct modldrv g_VBoxNetFltSolarisModule =
{
&mod_driverops, /* extern from kernel */
};
/**
*/
static struct modlinkage g_VBoxNetFltSolarisModLinkage =
{
{
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). */
/** Resources (bandwidth, CPU bindings, flow priority etc.) */
typedef struct VBOXNETFLTVNICTEMPLATE *PVBOXNETFLTVNICTEMPLATE;
/**
* VBOXNETFLTVNIC: Per-VNIC instance data.
*/
typedef struct VBOXNETFLTVNIC
{
/** Magic number (VBOXNETFLTVNIC_MAGIC). */
/** Whether we created the VNIC or not. */
bool fCreated;
/** Pointer to the VNIC template if any. */
/** Pointer to the VirtualBox interface instance. */
void *pvIf;
/** The MAC handle. */
/** The VNIC link ID. */
/** The MAC client handle */
/** The unicast address handle. */
/* The VNIC name. */
char szName[MAXLINKNAMESPECIFIER];
/** Handle to the next VNIC in the list. */
typedef struct VBOXNETFLTVNIC *PVBOXNETFLTVNIC;
/*******************************************************************************
* Global Variables *
*******************************************************************************/
/** Global Device handle we only support one instance. */
/** Global Mutex (actually an rw lock). */
/** The (common) global data. */
/** Global next-free VNIC Id (never decrements). */
static volatile uint64_t g_VBoxNetFltSolarisVNICId = 0;
/*******************************************************************************
* Internal Functions *
*******************************************************************************/
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 int vboxNetFltSolarisInitVNICTemplate(PVBOXNETFLTINS pThis, PVBOXNETFLTVNICTEMPLATE pVNICTemplate);
/**
* Kernel entry points
*/
int _init(void)
{
/*
* Prevent module autounloading.
*/
if (pModCtl)
else
/*
* Initialize IPRT.
*/
if (RT_SUCCESS(rc))
{
/*
* Initialize Solaris specific globals here.
*/
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.
*/
if (RT_SUCCESS(rc))
{
if (!rc)
return rc;
}
else
}
RTR0Term();
}
else
return RTErrConvertToErrno(rc);
}
int _fini(void)
{
int rc;
/*
* Undo the work done during start (in reverse order).
*/
if (RT_FAILURE(rc))
{
return EBUSY;
}
if (!rc)
{
{
}
RTR0Term();
}
return rc;
}
{
return rc;
}
/**
* Attach entry point, to attach a device to the system or resume it.
*
* @param pDip The module structure instance.
*
* @returns corresponding solaris error code.
*/
{
switch (enmCmd)
{
case DDI_ATTACH:
{
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.
*
* @returns corresponding solaris error code.
*/
{
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 **ppResult)
{
LogFlow((DEVICE_NAME ":VBoxNetFltSolarisGetInfo pDip=%p enmCmd=%d pArg=%p instance=%d\n", pDip, enmCmd, getminor((dev_t)pvArg)));
switch (enmCmd)
{
case DDI_INFO_DEVT2DEVINFO:
{
return DDI_SUCCESS;
}
case DDI_INFO_DEVT2INSTANCE:
{
return DDI_SUCCESS;
}
}
return DDI_FAILURE;
}
/**
* Create a solaris message block from the SG list.
*
* @param pThis The instance.
* @param pSG Pointer to the scatter-gather list.
*
* @returns Solaris message block.
*/
LOCAL inline mblk_t *vboxNetFltSolarisMBlkFromSG(PVBOXNETFLTINS pThis, PINTNETSG pSG, uint32_t fDst)
{
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.
*/
{
{
}
}
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.
*/
{
unsigned cSegs = 0;
cSegs++;
#ifdef PADD_RUNT_FRAMES_FROM_HOST
cSegs++;
#endif
}
/**
* 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)
{
LogFlow((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.
*/
unsigned iSeg = 0;
while (pCur)
{
if (cbSeg)
{
iSeg++;
}
}
#ifdef PADD_RUNT_FRAMES_FROM_HOST
{
}
#endif
LogFlow((DEVICE_NAME ":vboxNetFltSolarisMBlkToSG iSeg=%d pSG->cbTotal=%d msgdsize=%d\n", iSeg, pSG->cbTotal, msgdsize(pMsg)));
return VINF_SUCCESS;
}
/**
* Simple packet dump, used for internal debugging.
*
* @param pMsg Pointer to the message to analyze and dump.
*/
{
{
{
LogRel((DEVICE_NAME ":ICMP D=%.6Rhxs S=%.6Rhxs T=%04x\n", pb, pb + 6, RT_BE2H_U16(*(uint16_t *)(pb + 12))));
{
{
LogRel((DEVICE_NAME ":UDP bootp ack D=%.6Rhxs S=%.6Rhxs UDP_CheckSum=%04x Computex=%04x\n", pb, pb + 6,
}
}
}
else
{
}
}
{
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))));
}
{
}
{
}
{
}
else
{
LogRel((DEVICE_NAME ":Unknown EtherType=%x D=%.6Rhxs S=%.6Rhxs\n", RT_H2BE_U16(pEthHdr->EtherType), &pEthHdr->DstMac,
/* LogFlow((DEVICE_NAME ":%.*Rhxd\n", MBLKL(pMsg), pMsg->b_rptr)); */
}
}
/**
* Helper.
*/
{
}
/**
* 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)
{
LogFlow((DEVICE_NAME ":vboxNetFltSolarisRecv pvData=%p pMsg=%p fLoopback=%d cbData=%d\n", pvData, pMsg, fLoopback, pMsg ? MBLKL(pMsg) : 0));
/*
* Active? Retain the instance and increment the busy counter.
*/
{
return;
}
/*
* Route all received packets into the internal network.
*/
{
if (RT_SUCCESS(rc))
else
cFailed++;
}
if (RT_UNLIKELY(cFailed))
}
#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.
*/
{
switch (Type)
{
case MAC_NOTE_LINK:
{
{
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.
*/
{
if (!fIsVNIC)
else
{
if (RT_UNLIKELY(!hLowerMac))
{
LogRel((DEVICE_NAME ":vboxNetFltSolarisReportInfo failed to get lower MAC handle for '%s'\n", pThis->szName));
return VERR_INVALID_HANDLE;
}
}
#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.
*/
LogRel((DEVICE_NAME ":vboxNetFltSolarisReportInfo Warning! Failed to setup link notification hook.\n"));
#endif
{
pThis->pSwitchPort->pfnReportGsoCapabilities(pThis->pSwitchPort, 0, INTNETTRUNKDIR_WIRE | INTNETTRUNKDIR_HOST);
return VINF_SUCCESS;
}
else
return VERR_INTNET_FLT_IF_BUSY;
}
/**
* Initialize a VNIC, optionally from a template.
*
* @param pThis The instance.
* @param pVNIC Pointer to the VNIC.
* @param pVNICTemplate Pointer to the VNIC template initialize from, can be
* NULL.
*
* @returns VBox status code.
*/
{
/*
* Some paranoia.
*/
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 (pVNIC->pVNICTemplate)
{
return VINF_SUCCESS;
}
else
{
}
}
else
LogRel((DEVICE_NAME ":vboxNetFltSolarisInitVNIC failed to open mac client for '%s' rc=%d\n", pThis->szName, rc));
return rc;
}
/**
* 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)
{
LogFlow((DEVICE_NAME ":vboxNetFltSolarisInitVNICTemplate pThis=%p pVNICTemplate=%p\n", pThis, pVNICTemplate));
/*
* Get the VNIC template's datalink ID.
*/
if (RT_SUCCESS(rc))
{
/*
* Open the VNIC to obtain a MAC handle so as to retreive the VLAN ID.
*/
if (!rc)
{
/*
* Get the underlying linkname.
*/
if (RT_LIKELY(hPhysLinkHandle))
{
if (RT_SUCCESS(rc))
{
/*
* Now open the VNIC template to retrieve the VLAN Id & resources.
*/
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 */
);
{
LogFlow((DEVICE_NAME ":vboxNetFltSolarisInitVNICTemplate successfully init. VNIC template. szLinkName=%s\n",
return VINF_SUCCESS;
}
else
{
LogRel((DEVICE_NAME ":vboxNetFltSolarisInitVNICTemplate failed to open VNIC template. rc=%d\n", rc));
}
}
else
LogRel((DEVICE_NAME ":vboxNetFltSolarisInitVNICTemplate failed to copy link name of underlying interface. rc=%d\n", rc));
}
else
{
LogRel((DEVICE_NAME ":vboxNetFltSolarisInitVNICTemplate failed to get lower handle for VNIC template '%s'.\n", pThis->szName));
}
}
else
{
}
}
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.
*/
{
if (RT_UNLIKELY(!pVNIC))
return NULL;
return pVNIC;
}
/**
* Frees an allocated VNIC.
*
* @param pVNIC Pointer to the VNIC.
*/
{
}
/**
* 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.
*/
{
AssertMsgReturnVoid(pVNIC->u32Magic == VBOXNETFLTVNIC_MAGIC, ("pVNIC=%p u32Magic=%#x\n", pVNIC, pVNIC->u32Magic));
if (pVNIC)
{
{
{
}
}
if (pVNIC->hInterface)
{
}
{
}
if (pVNIC->pVNICTemplate)
{
}
}
}
/**
* 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.
*/
{
int rc = VERR_INVALID_STATE;
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().
*/
int MacSlot = 0;
if (pThis->u.s.fIsVNICTemplate)
{
{
return VERR_NO_MEMORY;
}
/*
* Initialize the VNIC template.
*/
if (RT_FAILURE(rc))
{
LogRel((DEVICE_NAME ":vboxNetFltSolarisCreateVNIC failed to initialize VNIC from VNIC template. rc=%Rrc\n", rc));
return rc;
}
#if 0
/*
* Required only if we're creating a VLAN interface & not a VNIC with a VLAN Id.
*/
if (uVLANId != VLAN_ID_NONE)
#endif
}
/*
* Create the VNIC under 'pszLinkName', which can be the one from the VNIC template or can
* be a physical interface.
*/
RTStrPrintf(pVNIC->szName, sizeof(pVNIC->szName), "%s%RU64", VBOXBOW_VNIC_NAME, g_VBoxNetFltSolarisVNICId);
rc = vnic_create(pVNIC->szName, pszLinkName, &AddrType, &MacLen, GuestMac.au8, &MacSlot, 0 /* Mac-Prefix Length */, uVLANId,
if (!rc)
{
/*
* Now try opening the created VNIC.
*/
if (!rc)
{
/*
* Initialize the VNIC from the physical interface or the VNIC template.
*/
if (RT_SUCCESS(rc))
{
LogFlow((DEVICE_NAME ":vboxNetFltSolarisCreateVNIC successfully created VNIC '%s' over '%s' with random mac %.6Rhxs\n",
return VINF_SUCCESS;
}
else
}
else
{
LogRel((DEVICE_NAME ":vboxNetFltSolarisCreateVNIC failed to open VNIC '%s' over '%s'. rc=%d\n", pVNIC->szName,
}
}
else
{
LogRel((DEVICE_NAME ":vboxNetFltSolarisCreateVNIC failed to create VNIC '%s' over '%s' rc=%d Diag=%d\n", pVNIC->szName,
}
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.
*/
{
/*
* 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.
*/
if (rc)
return VINF_SUCCESS;
return RTErrConvertFromErrno(rc);
}
/* -=-=-=-=-=- Common Hooks -=-=-=-=-=- */
{
/*
* Reactivate/quiesce the interface.
*/
if (fActive)
{
}
else
{
}
}
{
return VINF_SUCCESS;
}
{
return VINF_SUCCESS;
}
{
/*
* 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.
*/
{
}
}
{
/*
* do the actual VNIC creation if necessary in vboxNetFltPortOsConnectInterface().
*/
{
if (!rc)
{
LogFlow((DEVICE_NAME ":vboxNetFltOsInitInstance pThis=%p physical interface '%s' detected.\n", pThis, pThis->szName));
}
else
{
if (RTStrNCmp(pThis->szName, VBOXBOW_VNIC_TEMPLATE_NAME, sizeof(VBOXBOW_VNIC_TEMPLATE_NAME) - 1) == 0)
{
LogFlow((DEVICE_NAME ":vboxNetFltOsInitInstance pThis=%p VNIC template '%s' detected.\n", pThis, pThis->szName));
pThis->u.s.fIsVNICTemplate = true;
}
}
&& !pThis->u.s.fIsVNICTemplate)
LogFlow((DEVICE_NAME ":vboxNetFltOsInitInstance pThis=%p VNIC '%s' detected.\n", pThis, pThis->szName));
/*
* Report info. (host MAC address, promiscuous, GSO capabilities etc.) to IntNet.
*/
if (RT_FAILURE(rc))
}
else
{
LogRel((DEVICE_NAME ":vboxNetFltOsInitInstance failed to open link '%s'! rc=%d\n", pThis->szName, rc));
}
return rc;
}
{
/*
* Init. the solaris specific data.
*/
pThis->u.s.fIsVNICTemplate = false;
return VINF_SUCCESS;
}
{
/*
* @todo Think about this.
*/
return false;
}
{
/*
* Validate parameters.
*/
/*
* Xmit the packet down the appropriate VNIC interface.
*/
int rc = VINF_SUCCESS;
{
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;
}
else
{
rc = VERR_NO_MEMORY;
}
return rc;
}
{
LogFlow((DEVICE_NAME ":vboxNetFltPortOSNotifyMacAddress pszIf=%s pszVNIC=%s MAC=%.6Rhxs\n", pThis->szName,
/*
* Validate parameters.
*/
("Invalid pVNIC=%p magic=%#x (expected %#x)\n", pvIfData, VALID_PTR(pVNIC) ? pVNIC->u32Magic : 0, VBOXNETFLTVNIC_MAGIC));
/*
* Set the MAC address of the VNIC to the one used by the VM interface.
*/
int MacSlot = 0;
int rc = vnic_modify_addr(pVNIC->hLinkId, &AddrType, &MacLen, au8GuestMac, &MacSlot, 0 /* Mac-Prefix Length */, &Diag);
{
/*
* Remove existing unicast address and the RX hook.
*/
{
}
/*
* Add the primary unicast address and set the RX hook.
*/
/* uint16_t uVLANId = pVNIC->pVNICTemplate ? pVNIC->pVNICTemplate->uVLANId : 0; */
rc = mac_unicast_add(pVNIC->hClient, NULL, MAC_UNICAST_PRIMARY, &pVNIC->hUnicast, 0 /* VLAN Id */, &MacDiag);
{
/*
* 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.
*/
LogFlow((DEVICE_NAME ":vboxNetFltPortOsNotifyMacAddress successfully added unicast address %.6Rhxs\n", pMac));
}
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.
*/
{
LogRel((DEVICE_NAME ":vboxNetFltPortOsNotifyMacAddress: failed! a VNIC with mac %.6Rhxs probably already exists.",
LogRel((DEVICE_NAME ":vboxNetFltPortOsNotifyMacAddress: This NIC cannot establish connection. szName=%s szVNIC=%s\n",
}
else
LogRel((DEVICE_NAME ":vboxNetFltPortOsNotifyMacAddress failed! mac %.6Rhxs rc=%d Diag=%d\n", pMac, rc, Diag));
}
}
{
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.
*/
|| pThis->u.s.fIsVNICTemplate)
{
if (RT_SUCCESS(rc))
{
/*
*/
/*
* Add the created VNIC to the list of VNICs we manage.
*/
return VINF_SUCCESS;
}
else
}
else
{
/*
* This is a VNIC passed to us, use it directly.
*/
{
if (!rc)
{
/*
* Obtain the data link ID for this VNIC, it's needed for modifying the MAC address among other things.
*/
if (RT_SUCCESS(rc))
{
/*
* Initialize the VNIC and add it to the list of managed VNICs.
*/
if (!rc)
{
return VINF_SUCCESS;
}
else
}
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));
}
}
else
{
rc = VERR_NO_MEMORY;
}
}
return rc;
}
{
("Invalid pvIfData=%p magic=%#x (expected %#x)\n", pvIfData, pVNIC ? pVNIC->u32Magic : 0, VBOXNETFLTVNIC_MAGIC),
/*
* If the underlying interface is not a VNIC, we need to delete the created VNIC.
*/
{
/*
* Remove the VNIC from the list, destroy and free it.
*/
}
return VINF_SUCCESS;
}