VBoxNetAdp.c revision 6af5a377dcdc4437fa51e183a5a8dad78abf2ec0
/* $Id$ */
/** @file
* VBoxNetAdp - Virtual Network Adapter Driver (Host), Common Code.
*/
/*
* Copyright (C) 2008-2009 Sun Microsystems, Inc.
*
* 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.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
* Clara, CA 95054 USA or visit http://www.sun.com if you need
* additional information or have any questions.
*/
/*******************************************************************************
* Header Files *
*******************************************************************************/
#define LOG_GROUP LOG_GROUP_NET_TAP_DRV
#include "VBoxNetAdpInternal.h"
#include <iprt/spinlock.h>
#ifndef RT_OS_SOLARIS
#include <net/ethernet.h>
#include <net/if_ether.h>
#include <net/if_types.h>
#endif
/*******************************************************************************
* Defined Constants And Macros *
*******************************************************************************/
#define IFPORT_2_VBOXNETADP(pIfPort) \
/**
* Generate a suitable MAC address.
*
* @param pThis The instance.
* @param pMac Where to return the MAC address.
*/
{
#if 0 /* Use a locally administered version of the OUI we use for the guest NICs. */
#else /* this is what \0vb comes down to. It seems to be unassigned atm. */
#endif
}
/**
* Gets the enmState member atomically.
*
* Used for all reads.
*
* @returns The enmState value.
* @param pThis The instance.
*/
{
}
/**
* Sets the enmState member atomically.
*
* Used for all updates.
*
* @param pThis The instance.
* @param enmNewState The new value.
*/
{
Log(("vboxNetAdpSetState: pThis=%p, state change: %d -> %d.\n", pThis, vboxNetAdpGetState(pThis), enmNewState));
}
/**
* Sets the enmState member atomically.
*
* Used for all updates.
*
* @param pThis The instance.
* @param enmNewState The new value.
*/
{
}
/**
* Gets the enmState member with locking.
*
* Used for all reads.
*
* @returns The enmState value.
* @param pThis The instance.
*/
{
return enmState;
}
/**
* Checks and sets the enmState member atomically.
*
* Used for all updates.
*
* @returns true if the state has been changed.
* @param pThis The instance.
* @param enmNewState The new value.
*/
DECLINLINE(bool) vboxNetAdpCheckAndSetState(PVBOXNETADP pThis, VBOXNETADPSTATE enmOldState, VBOXNETADPSTATE enmNewState)
{
bool fRc = true; /* be optimistic */
if (enmActualState == enmOldState)
else
fRc = false;
if (fRc)
Log(("vboxNetAdpCheckAndSetState: pThis=%p, state changed: %d -> %d.\n", pThis, enmOldState, enmNewState));
else
Log(("vboxNetAdpCheckAndSetState: pThis=%p, no state change: %d != %d (expected).\n", pThis, enmActualState, enmOldState));
return fRc;
}
{
unsigned i;
{
if (vboxNetAdpGetState(pThis)
{
return pThis;
}
}
return NULL;
}
/**
* Releases a reference to the specified instance.
*
* @param pThis The instance.
* @param fBusy Whether the busy counter should be decremented too.
*/
{
/*
* Paranoid Android.
*/
/*
* The object reference counting.
*/
}
/**
* Decrements the busy counter and does idle wakeup.
*
* @param pThis The instance.
*/
{
/*
* Paranoid Android.
*/
if (!cBusy)
{
}
else
}
/**
* Retains a reference to the specified instance.
*
* @param pThis The instance.
*/
{
/*
* Paranoid Android.
*/
/*
* Retain the object.
*/
}
/**
* Increments busy counter.
*
* @param pThis The instance.
*/
{
/*
* Are we vigilant enough?
*/
}
/**
* Checks if receive is possible and increases busy and ref counters if so.
*
* @param pThis The instance.
*/
{
bool fCanReceive = false;
/*
* Input validation.
*/
{
fCanReceive = true;
}
return fCanReceive;
}
/**
*
* @param pThis The instance.
*/
{
/*
* Input validation.
*/
Log(("vboxNetAdpReceive: forwarding packet to internal net...\n"));
}
/**
* Decreases busy and ref counters.
*
* @param pThis The instance.
*/
{
Log(("vboxNetAdpCancelReceive: cancelled.\n"));
}
#ifdef RT_WITH_W64_UNWIND_HACK
# if defined(RT_OS_WINDOWS) && defined(RT_ARCH_AMD64)
NETADP_DECL_CALLBACK(int) NETADP_CALLBACK(vboxNetAdpPortXmit)(PINTNETTRUNKIFPORT pIfPort, PINTNETSG pSG, uint32_t fDst);
NETADP_DECL_CALLBACK(bool) NETADP_CALLBACK(vboxNetAdpPortIsPromiscuous)(PINTNETTRUNKIFPORT pIfPort);
NETADP_DECL_CALLBACK(void) NETADP_CALLBACK(vboxNetAdpPortGetMacAddress)(PINTNETTRUNKIFPORT pIfPort, PRTMAC pMac);
NETADP_DECL_CALLBACK(bool) NETADP_CALLBACK(vboxNetAdpPortIsHostMac)(PINTNETTRUNKIFPORT pIfPort, PCRTMAC pMac);
NETADP_DECL_CALLBACK(int) NETADP_CALLBACK(vboxNetAdpPortWaitForIdle)(PINTNETTRUNKIFPORT pIfPort, uint32_t cMillies);
NETADP_DECL_CALLBACK(bool) NETADP_CALLBACK(vboxNetAdpPortSetActive)(PINTNETTRUNKIFPORT pIfPort, bool fActive);
NETADP_DECL_CALLBACK(void) NETADP_CALLBACK(vboxNetAdpPortDisconnectAndRelease)(PINTNETTRUNKIFPORT pIfPort);
# else
# error "UNSUPPORTED (RT_WITH_W64_UNWIND_HACK)"
# endif
#else
#endif
/**
* @copydoc INTNETTRUNKIFPORT::pfnXmit
*/
NETADP_DECL_CALLBACK(int) vboxNetAdpPortXmit(PINTNETTRUNKIFPORT pIfPort, PINTNETSG pSG, uint32_t fDst)
{
int rc = VINF_SUCCESS;
/*
* Input validation.
*/
/*
*/
{
Log(("vboxNetAdpReceive: Dropping incoming packet for inactive interface %s.\n",
return VERR_INVALID_STATE;
}
return rc;
}
/**
* @copydoc INTNETTRUNKIFPORT::pfnIsPromiscuous
*/
{
/*
* Input validation.
*/
/*
* Ask the OS specific code.
*/
return vboxNetAdpPortOsIsPromiscuous(pThis);
}
/**
* @copydoc INTNETTRUNKIFPORT::pfnGetMacAddress
*/
{
/*
* Input validation.
*/
/*
* Forward the question to the OS specific code.
*/
}
/**
* @copydoc INTNETTRUNKIFPORT::pfnIsHostMac
*/
{
/*
* Input validation.
*/
/*
* Ask the OS specific code.
*/
}
/**
* @copydoc INTNETTRUNKIFPORT::pfnWaitForIdle
*/
{
int rc;
/*
* Input validation.
*/
/*
* Go to sleep on the semaphore after checking the busy count.
*/
rc = VINF_SUCCESS;
return rc;
}
/**
* @copydoc INTNETTRUNKIFPORT::pfnSetActive
*/
{
bool fPreviouslyActive;
/*
* Input validation.
*/
Log(("vboxNetAdpPortSetActive: pThis=%p, fActive=%d, state before: %d.\n", pThis, fActive, vboxNetAdpGetState(pThis)));
if (fPreviouslyActive != fActive)
{
switch (vboxNetAdpGetState(pThis))
{
break;
case kVBoxNetAdpState_Active:
break;
default:
break;
}
}
return fPreviouslyActive;
}
/**
* @copydoc INTNETTRUNKIFPORT::pfnDisconnectAndRelease
*/
{
/*
* Serious paranoia.
*/
/*
* Disconnect and release it.
*/
//Assert(vboxNetAdpGetState(pThis) == kVBoxNetAdpState_Connected);
}
/**
* @copydoc INTNETTRUNKIFPORT::pfnRelease
*/
{
}
/**
* @copydoc INTNETTRUNKIFPORT::pfnRetain
*/
{
}
{
int rc;
unsigned i;
PVBOXNETADPGLOBALS pGlobals = (PVBOXNETADPGLOBALS)((uint8_t *)pIfFactory - RT_OFFSETOF(VBOXNETADPGLOBALS, TrunkFactory));
{
{
/* Found an empty slot -- use it. */
return rc;
}
}
/* All slots in adapter array are busy. */
return VERR_OUT_OF_RESOURCES;
}
{
int rc = VINF_SUCCESS;
{
return VERR_INTNET_FLT_IF_BUSY;
}
return rc;
}
/**
* Connects the instance to the specified switch port.
*
* Called while owning the lock. We're ASSUMING that the internal
* networking code is already owning an recursive mutex, so, there
* will be no deadlocks when vboxNetAdpOsConnectIt calls back into
* it for setting preferences.
*
* @returns VBox status code.
* @param pThis The instance.
* @param pSwitchPort The port on the internal network 'switch'.
* @param ppIfPort Where to return our port interface.
*/
static int vboxNetAdpConnectIt(PVBOXNETADP pThis, PINTNETTRUNKSWPORT pSwitchPort, PINTNETTRUNKIFPORT *ppIfPort)
{
int rc;
/*
* Validate state.
*/
/*
* Do the job.
* Note that we're calling the os stuff while owning the semaphore here.
*/
if (RT_SUCCESS(rc))
{
}
else
return rc;
}
/**
* @copydoc INTNETTRUNKFACTORY::pfnCreateAndConnect
*/
static DECLCALLBACK(int) vboxNetAdpFactoryCreateAndConnect(PINTNETTRUNKFACTORY pIfFactory, const char *pszName,
{
int rc;
PVBOXNETADPGLOBALS pGlobals = (PVBOXNETADPGLOBALS)((uint8_t *)pIfFactory - RT_OFFSETOF(VBOXNETADPGLOBALS, TrunkFactory));
/*
* Find instance, check if busy, connect if not.
*/
if (pThis)
{
{
vboxNetAdpSetStateWithLock(pThis, RT_SUCCESS(rc) ? kVBoxNetAdpState_Connected : kVBoxNetAdpState_Available);
}
else
}
else
return rc;
}
/**
* @copydoc INTNETTRUNKFACTORY::pfnRelease
*/
{
PVBOXNETADPGLOBALS pGlobals = (PVBOXNETADPGLOBALS)((uint8_t *)pIfFactory - RT_OFFSETOF(VBOXNETADPGLOBALS, TrunkFactory));
}
/**
* Implements the SUPDRV component factor interface query method.
*
* @returns Pointer to an interface. NULL if not supported.
*
* @param pSupDrvFactory Pointer to the component factory registration structure.
* @param pSession The session - unused.
* @param pszInterfaceUuid The factory interface id.
*/
static DECLCALLBACK(void *) vboxNetAdpQueryFactoryInterface(PCSUPDRVFACTORY pSupDrvFactory, PSUPDRVSESSION pSession, const char *pszInterfaceUuid)
{
PVBOXNETADPGLOBALS pGlobals = (PVBOXNETADPGLOBALS)((uint8_t *)pSupDrvFactory - RT_OFFSETOF(VBOXNETADPGLOBALS, SupDrvFactory));
/*
* Convert the UUID strings and compare them.
*/
if (RT_SUCCESS(rc))
{
{
return &pGlobals->TrunkFactory;
}
#ifdef LOG_ENABLED
else
#endif
}
else
return NULL;
}
/**
* Checks whether the VBoxNetAdp wossname can be unloaded.
*
* This will return false if someone is currently using the module.
*
* @returns true if it's relatively safe to unload it, otherwise false.
* @param pGlobals Pointer to the globals.
*/
{
int rc;
unsigned i;
bool fRc = true; /* Assume it can be unloaded. */
{
{
fRc = false;
break; /* We already know the answer. */
}
}
}
/**
* tries to deinitialize Idc
* we separate the globals settings "base" which is actually
* "general" globals settings except for Idc, and idc.
* This is needed for windows filter driver, which gets loaded prior to VBoxDrv,
* thus it's not possible to make idc initialization from the driver startup routine for it,
* though the "base is still needed for the driver to functions".
* @param pGlobals
* @return VINF_SUCCESS on succes, VERR_WRONG_ORDER if we're busy.
*/
{
int rc;
/*
* Check before trying to deregister the factory.
*/
if (!vboxNetAdpCanUnload(pGlobals))
return VERR_WRONG_ORDER;
/*
* Disconnect from SUPDRV and check that nobody raced us,
* reconnect if that should happen.
*/
if (!vboxNetAdpCanUnload(pGlobals))
{
return VERR_WRONG_ORDER;
}
return rc;
}
{
int rc;
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
return rc;
}
}
}
return rc;
}
{
{
}
{
}
}
/**
* performs "base" globals deinitialization
* we separate the globals settings "base" which is actually
* "general" globals settings except for Idc, and idc.
* This is needed for windows filter driver, which gets loaded prior to VBoxDrv,
* thus it's not possible to make idc initialization from the driver startup routine for it,
* though the "base is still needed for the driver to functions".
* @param pGlobals
* @return none
*/
{
int i;
/*
* Release resources.
*/
#ifdef VBOXNETADP_STATIC_CONFIG
#endif
}
/**
* Called by the native part when the OS wants the driver to unload.
*
* @returns VINF_SUCCESS on succes, VERR_WRONG_ORDER if we're busy.
*
* @param pGlobals Pointer to the globals.
*/
{
if(RT_SUCCESS(rc))
{
}
return rc;
}
/**
* performs the "base" globals initialization
* we separate the globals initialization to globals "base" initialization which is actually
* "general" globals initialization except for Idc not being initialized, and idc initialization.
* This is needed for windows filter driver, which gets loaded prior to VBoxDrv,
* thus it's not possible to make idc initialization from the driver startup routine for it.
*
* @returns VBox status code.
* @param pGlobals Pointer to the globals. */
{
/*
* Initialize the common portions of the structure.
*/
int i;
if (RT_SUCCESS(rc))
{
{
if (RT_FAILURE(rc))
{
/* Clean up. */
while (--i >= 0)
return rc;
}
}
}
return rc;
}
/**
* performs the Idc initialization
* we separate the globals initialization to globals "base" initialization which is actually
* "general" globals initialization except for Idc not being initialized, and idc initialization.
* This is needed for windows filter driver, which gets loaded prior to VBoxDrv,
* thus it's not possible to make idc initialization from the driver startup routine for it.
*
* @returns VBox status code.
* @param pGlobals Pointer to the globals. */
{
int rc;
/*
* Establish a connection to SUPDRV and register our component factory.
*/
rc = SUPR0IdcOpen(&pGlobals->SupDrvIDC, 0 /* iReqVersion = default */, 0 /* iMinVersion = default */, NULL, NULL, NULL);
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
/* @todo REMOVE ME! */
if (RT_FAILURE(rc))
return rc;
}
/* bail out. */
}
return rc;
}
/**
*
* It will initialize the common parts of the globals, assuming the caller
* has already taken care of the OS specific bits.
*
* @returns VBox status code.
* @param pGlobals Pointer to the globals.
*/
{
/*
* Initialize the common portions of the structure.
*/
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
return rc;
}
/* bail out. */
}
return rc;
}