DrvTAP.cpp revision faef14ef4b633101dd3d9bf3fe47977a7b0abf51
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis * DrvTAP - Universal TAP network transport driver.
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis * Copyright (C) 2006-2013 Oracle Corporation
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis * This file is part of VirtualBox Open Source Edition (OSE), as
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis * available from http://www.virtualbox.org. This file is free software;
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis * you can redistribute it and/or modify it under the terms of the GNU
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis * General Public License (GPL) as published by the Free Software
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis * Foundation, in version 2 as it comes in the "COPYING" file of the
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis/*******************************************************************************
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis* Header Files *
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis*******************************************************************************/
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis/*******************************************************************************
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis* Structures and Typedefs *
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis*******************************************************************************/
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis * TAP driver instance data.
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis * @implements PDMINETWORKUP
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /** The network interface. */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /** The network interface. */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /** Pointer to the driver instance. */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /** TAP device file handle. */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /** The configured TAP device name. */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /** IP device file handle (/dev/udp). */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /** Whether device name is obtained from setup application. */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /** TAP setup application. */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /** TAP terminate application. */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /** The write end of the control pipe. */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /** The read end of the control pipe. */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /** Reader thread. */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /** @todo The transmit thread. */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /** Transmit lock used by drvTAPNetworkUp_BeginXmit. */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /** Number of sent packets. */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /** Number of sent bytes. */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /** Number of received packets. */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /** Number of received bytes. */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /** Profiling packet transmit runs. */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /** Profiling packet receive runs. */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#endif /* VBOX_WITH_STATISTICS */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /** The nano ts of the last transfer. */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /** The nano ts of the last receive. */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis/** Converts a pointer to TAP::INetworkUp to a PRDVTAP. */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis#define PDMINETWORKUP_2_DRVTAP(pInterface) ( (PDRVTAP)((uintptr_t)pInterface - RT_OFFSETOF(DRVTAP, INetworkUp)) )
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis/*******************************************************************************
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis* Internal Functions *
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis*******************************************************************************/
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtisstatic int SolarisTAPAttach(PDRVTAP pThis);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis * @interface_method_impl{PDMINETWORKUP,pfnBeginXmit}
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtisstatic DECLCALLBACK(int) drvTAPNetworkUp_BeginXmit(PPDMINETWORKUP pInterface, bool fOnWorkerThread)
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis PDRVTAP pThis = PDMINETWORKUP_2_DRVTAP(pInterface);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis int rc = RTCritSectTryEnter(&pThis->XmitLock);
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis /** @todo XMIT thread */
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis * @interface_method_impl{PDMINETWORKUP,pfnAllocBuf}
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtisstatic DECLCALLBACK(int) drvTAPNetworkUp_AllocBuf(PPDMINETWORKUP pInterface, size_t cbMin,
25c28e83beb90e7c80452a7c818c5e6f73a07dc8Piotr Jasiukajtis PCPDMNETWORKGSO pGso, PPPDMSCATTERGATHER ppSgBuf)
if (!pSgBuf)
return VERR_NO_MEMORY;
if (!pGso)
return VINF_SUCCESS;
static DECLCALLBACK(int) drvTAPNetworkUp_FreeBuf(PPDMINETWORKUP pInterface, PPDMSCATTERGATHER pSgBuf)
if (pSgBuf)
return VINF_SUCCESS;
static DECLCALLBACK(int) drvTAPNetworkUp_SendBuf(PPDMINETWORKUP pInterface, PPDMSCATTERGATHER pSgBuf, bool fOnWorkerThread)
int rc;
#ifdef LOG_ENABLED
return rc;
static DECLCALLBACK(void) drvTAPNetworkUp_SetPromiscuousMode(PPDMINETWORKUP pInterface, bool fPromiscuous)
static DECLCALLBACK(void) drvTAPNetworkUp_NotifyLinkChanged(PPDMINETWORKUP pInterface, PDMNETWORKLINKSTATE enmLinkState)
return VINF_SUCCESS;
errno=0;
if ( rc > 0
#ifdef LOG_ENABLED
else if ( rc > 0
LogFlow(("drvTAPAsyncIoThread: Control message: enmState=%d revents=%#x\n", pThread->enmState, aFDs[1].revents));
char ch;
Log(("rc=%d revents=%#x,%#x errno=%p %s\n", rc, aFDs[0].revents, aFDs[1].revents, errno, strerror(errno)));
AssertMsgFailed(("rc=%d revents=%#x,%#x errno=%p %s\n", rc, aFDs[0].revents, aFDs[1].revents, errno, strerror(errno)));
return VINF_SUCCESS;
return VINF_SUCCESS;
#if defined(RT_OS_SOLARIS)
* Calls OS-specific TAP setup application/script.
if (pfSetupHandle == 0)
return VERR_HOSTIF_INIT_FAILED;
return VERR_HOSTIF_INIT_FAILED;
return VERR_HOSTIF_INIT_FAILED;
return VERR_HOSTIF_INIT_FAILED;
return VINF_SUCCESS;
* Calls OS-specific TAP terminate application/script.
Log2(("Starting TAP terminate application: %s %s\n", pThis->pszTerminateApplication, pThis->pszDeviceName));
return VINF_SUCCESS;
LogRel(("TAP#%d: Error running TAP terminate application: %s\n", pThis->pDrvIns->iInstance, pThis->pszTerminateApplication));
LogRel(("TAP#%d: RTProcWait failed for: %s\n", pThis->pDrvIns->iInstance, pThis->pszTerminateApplication));
LogRel(("TAP#%d: Failed to fork() process for running TAP terminate application: %s\n", pThis->pDrvIns->iInstance,
return VERR_HOSTIF_TERM_FAILED;
#ifdef RT_OS_SOLARIS
if (IPFileDes < 0)
if (TapFileDes < 0)
if (iPPA < 0)
if (!InterfaceFD)
LogRel(("TAP#%d: Failed to get interface flags after setting PPA. errno=%d\n", pThis->pDrvIns->iInstance, errno));
#ifdef VBOX_SOLARIS_TAP_ARP
LogRel(("TAP#%d: Failed to push ARP to Interface FD. errno=%d\n", pThis->pDrvIns->iInstance, errno));
if (ARPFileDes < 0)
LogRel(("TAP#%d: Failed to open for /dev/tap for ARP. errno=%d", pThis->pDrvIns->iInstance, errno));
#ifdef VBOX_SOLARIS_TAP_ARP
#ifdef VBOX_SOLARIS_TAP_ARP
#ifdef VBOX_SOLARIS_TAP_ARP
#ifdef VBOX_SOLARIS_TAP_ARP
return VINF_SUCCESS;
return NULL;
int rc;
#ifdef RT_OS_SOLARIS
/** @todo r=bird: This *does* need checking against ConsoleImpl2.cpp if used on non-solaris systems. */
#ifdef RT_OS_SOLARIS
#ifdef VBOX_WITH_STATISTICS
#ifdef RT_OS_SOLARIS
#ifdef VBOX_WITH_STATISTICS
PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatPktSent, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of sent packets.", "/Drivers/TAP%d/Packets/Sent", pDrvIns->iInstance);
PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatPktSentBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of sent bytes.", "/Drivers/TAP%d/Bytes/Sent", pDrvIns->iInstance);
PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatPktRecv, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of received packets.", "/Drivers/TAP%d/Packets/Received", pDrvIns->iInstance);
PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatPktRecvBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Number of received bytes.", "/Drivers/TAP%d/Bytes/Received", pDrvIns->iInstance);
PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatTransmit, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling packet transmit runs.", "/Drivers/TAP%d/Transmit", pDrvIns->iInstance);
PDMDrvHlpSTAMRegisterF(pDrvIns, &pThis->StatReceive, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling packet receive runs.", "/Drivers/TAP%d/Receive", pDrvIns->iInstance);
if (!CFGMR3AreValuesValid(pCfg, "Device\0InitProg\0TermProg\0FileHandle\0TAPSetupApplication\0TAPTerminateApplication\0MAC"))
int rc;
#if defined(RT_OS_SOLARIS) /** @todo Other platforms' TAP code should be moved here from ConsoleImpl. */
return PDMDRV_SET_ERROR(pDrvIns, rc, N_("Configuration error: failed to query \"TAPTerminateApplication\""));
return PDMDRV_SET_ERROR(pDrvIns, rc, N_("Configuration error: failed to query \"TAPTerminateApplication\""));
return rc;
rc = PDMDrvHlpThreadCreate(pDrvIns, &pThis->pThread, pThis, drvTAPAsyncIoThread, drvTapAsyncIoWakeup, 128 * _1K, RTTHREADTYPE_IO, "TAP");
return rc;
sizeof(DRVTAP),
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,
NULL,