DevVirtioNet.cpp revision 9bb98d54790a98dad0ad6d9bdc5d319b6fdf0bff
/* $Id$ */
/** @file
* DevVirtioNet - Virtio Network Device
*
*/
/*
* Copyright (C) 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.
*/
#define LOG_GROUP LOG_GROUP_DEV_VIRTIO_NET
#ifdef IN_RING3
#endif /* IN_RING3 */
#include <iprt/semaphore.h>
#include "../Builtins.h"
#if 0
#endif
// TODO: move declarations to the header file: #include "DevVirtioNet.h"
#define IFACE_TO_STATE(pIface, ifaceName) ((VPCISTATE *)((char*)pIface - RT_OFFSETOF(VPCISTATE, ifaceName)))
#if 0
/* Little helpers ************************************************************/
#define htonl(x) ASMByteSwapU32(x)
#define E1K_RELOCATE(p, o) *(RTHCUINTPTR *)&p += o
#define E1K_INC_CNT32(cnt) \
do { \
if (cnt < UINT32_MAX) \
cnt++; \
} while (0)
do { \
u64Cnt = UINT64_MAX; \
} while (0)
#ifdef E1K_INT_STATS
#else /* E1K_INT_STATS */
# define E1K_INC_ISTAT_CNT(cnt)
#endif /* E1K_INT_STATS */
#endif
/*****************************************************************************/
/*****************************************************************************/
struct VRingDesc
{
};
struct VRing
{
};
struct VQueue
{
};
enum VirtioDeviceType
{
VIRTIO_NET_ID = 0,
VIRTIO_BLK_ID = 1
};
struct VPCIState_st
{
/* Read-only part, never changes after initialization. */
/** TODO */
/** Base port of I/O space region. */
/** Status LED. */
#if defined(VBOX_WITH_STATISTICS)
#endif /* VBOX_WITH_STATISTICS */
};
typedef struct VPCIState_st VPCISTATE;
struct VirtioPCIDevices
{
unsigned nQueues;
const char *pcszName;
const char *pcszNameFmt;
} g_VPCIDevices[] =
{
/* Vendor Device SSVendor SubSys Class Name */
};
/*****************************************************************************/
#define VPCI_HOST_FEATURES 0x0
#define VPCI_GUEST_FEATURES 0x4
#define VPCI_QUEUE_PFN 0x8
#define VPCI_QUEUE_NUM 0xC
#define VPCI_QUEUE_SEL 0xE
#define VPCI_QUEUE_NOTIFY 0x10
#define VPCI_STATUS 0x12
#define VPCI_ISR 0x13
#define VPCI_ISR_QUEUE 0x1
#define VPCI_ISR_CONFIG 0x3
#define VPCI_CONFIG 0x14
/** @todo use+extend RTNETIPV4 */
/** @todo use+extend RTNETTCP */
#define VNET_SAVEDSTATE_VERSION 1
#ifndef VBOX_DEVICE_STRUCT_TESTCASE
/* Forward declarations ******************************************************/
PDMBOTHCBDECL(int) vpciIOPortIn (PPDMDEVINS pDevIns, void *pvUser, RTIOPORT port, uint32_t *pu32, unsigned cb);
PDMBOTHCBDECL(int) vpciIOPortOut(PPDMDEVINS pDevIns, void *pvUser, RTIOPORT port, uint32_t u32, unsigned cb);
/**
* Arm a timer.
*
* @param pState Pointer to the device state structure.
* @param pTimer Pointer to the timer.
* @param uExpireIn Expiration interval in microseconds.
*/
{
Log2(("%s Arming timer to fire in %d usec...\n",
TMTimerGet(pTimer));
}
{
}
{
}
/**
* Raise interrupt.
*
* @param pState The device state structure.
* @param rcBusy Status code to return when the critical section is busy.
* @param u8IntCause Interrupt cause bit mask to set in PCI ISR port.
*/
{
return rc;
return VINF_SUCCESS;
}
/**
* Lower interrupt.
*
* @param pState The device state structure.
*/
{
}
/**
* Port I/O Handler for IN operations.
*
* @returns VBox status code.
*
* @param pDevIns The device instance.
* @param pvUser Pointer to the device state structure.
* @param port Port number used for the IN operation.
* @param pu32 Where to store the result.
* @param cb Number of bytes read.
* @thread EMT
*/
{
int rc = VINF_SUCCESS;
switch (port)
{
case VPCI_HOST_FEATURES:
/* Tell the guest what features we support. */
break;
case VPCI_GUEST_FEATURES:
break;
case VPCI_QUEUE_PFN:
break;
case VPCI_QUEUE_NUM:
break;
case VPCI_QUEUE_SEL:
break;
case VPCI_STATUS:
break;
case VPCI_ISR:
break;
default:
if (port >= VPCI_CONFIG)
else
{
*pu32 = 0xFFFFFFFF;
rc = PDMDeviceDBGFStop(pDevIns, RT_SRC_POS, "%s virtioIOPortIn: no valid port at offset port=%RTiop cb=%08x\n", szInst, port, cb);
}
break;
}
return rc;
}
/**
* Port I/O Handler for OUT operations.
*
* @returns VBox status code.
*
* @param pDevIns The device instance.
* @param pvUser User argument.
* @param Port Port number used for the IN operation.
* @param u32 The value to output.
* @param cb The value size in bytes.
* @thread EMT
*/
{
int rc = VINF_SUCCESS;
switch (port)
{
case VPCI_GUEST_FEATURES:
// TODO: Feature negotiation code goes here.
// The guest may potentially desire features we don't support!
break;
case VPCI_QUEUE_PFN:
/*
* The guest is responsible for allocating the pages for queues,
* here it provides us with the page number of descriptor table.
* Note that we provide the size of the queue to the guest via
* VIRTIO_PCI_QUEUE_NUM.
*/
break;
case VPCI_QUEUE_SEL:
u32 &= 0xFFFF;
else
break;
case VPCI_QUEUE_NOTIFY:
// TODO
break;
case VPCI_STATUS:
u32 &= 0xFF;
/* Writing 0 to the status port triggers device reset. */
if (u32 == 0)
break;
default:
if (port >= VPCI_CONFIG)
else
rc = PDMDeviceDBGFStop(pDevIns, RT_SRC_POS, "%s virtioIOPortOut: no valid port at offset port=%RTiop cb=%08x\n", szInst, port, cb);
break;
}
return rc;
}
#ifdef IN_RING3
// Common
/**
* Map PCI I/O region.
*
* @return VBox status code.
* @param pPciDev Pointer to PCI device. Use pPciDev->pDevIns to get the device instance.
* @param iRegion The region number.
* @param GCPhysAddress Physical address of the region. If iType is PCI_ADDRESS_SPACE_IO, this is an
* I/O port, else it's a physical address.
* This address is *NOT* relative to pci_mem_base like earlier!
* @param cb Region size.
* @param enmType One of the PCI_ADDRESS_SPACE_* values.
* @thread EMT
*/
{
int rc;
if (enmType != PCI_ADDRESS_SPACE_IO)
{
/* We should never get here */
AssertMsgFailed(("Invalid PCI address space param in map callback"));
return VERR_INTERNAL_ERROR;
}
#if 0
#endif
return rc;
}
/**
* Provides interfaces to the driver.
*
* @returns Pointer to interface. NULL if the interface is not supported.
* @param pInterface Pointer to this interface structure.
* @param enmInterface The requested interface identification.
* @thread EMT
*/
static DECLCALLBACK(void *) vpciQueryInterface(struct PDMIBASE *pInterface, PDMINTERFACE enmInterface)
{
switch (enmInterface)
{
case PDMINTERFACE_BASE:
case PDMINTERFACE_LED_PORTS:
default:
return NULL;
}
}
/**
* Gets the pointer to the status LED of a unit.
*
* @returns VBox status code.
* @param pInterface Pointer to the interface structure.
* @param iLUN The unit which status LED we desire.
* @param ppLed Where to store the LED pointer.
* @thread EMT
*/
static DECLCALLBACK(int) vpciQueryStatusLed(PPDMILEDPORTS pInterface, unsigned iLUN, PPDMLED *ppLed)
{
int rc = VERR_PDM_LUN_NOT_FOUND;
if (iLUN == 0)
{
rc = VINF_SUCCESS;
}
return rc;
}
/**
* Sets 8-bit register in PCI configuration space.
* @param refPciDev The PCI device.
* @param uOffset The register offset.
* @param u16Value The value to store in the register.
* @thread EMT
*/
{
}
/**
* Sets 16-bit register in PCI configuration space.
* @param refPciDev The PCI device.
* @param uOffset The register offset.
* @param u16Value The value to store in the register.
* @thread EMT
*/
{
}
/**
* Sets 32-bit register in PCI configuration space.
* @param refPciDev The PCI device.
* @param uOffset The register offset.
* @param u32Value The value to store in the register.
* @thread EMT
*/
{
}
/**
* Set PCI configuration space registers.
*
* @param pci Reference to PCI device structure.
* @thread EMT
*/
{
/* Configure PCI Device, assume 32-bit mode ******************************/
virtioPCICfgSetU16(pci, VBOX_PCI_SUBSYSTEM_VENDOR_ID, g_VPCIDevices[enmType].uPCISubsystemVendorId);
/* ABI version, must be equal 0 as of 2.6.30 kernel. */
/* Ethernet adapter */
/* Interrupt Pin: INTA# */
}
// TODO: header
unsigned uConfigSize)
{
int rc = VINF_SUCCESS;
/* Init handles and log related stuff. */
RTStrPrintf(pState->szInstance, sizeof(pState->szInstance), g_VPCIDevices[enmDevType].pcszNameFmt, iInstance);
/* Allocate queues */
/* Initialize critical section. */
if (RT_FAILURE(rc))
return rc;
/* Set PCI config registers */
/* Register PCI device */
if (RT_FAILURE(rc))
return rc;
/* Map our ports to IO space. */
if (RT_FAILURE(rc))
return rc;
/* Status driver */
if (RT_FAILURE(rc))
pState->pLedsConnector = (PPDMILEDCONNECTORS)pBase->pfnQueryInterface(pBase, PDMINTERFACE_LED_CONNECTORS);
#if defined(VBOX_WITH_STATISTICS)
PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatIOReadGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling IO reads in GC", "/Devices/VNet%d/IO/ReadGC", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatIOReadHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling IO reads in HC", "/Devices/VNet%d/IO/ReadHC", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatIOWriteGC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling IO writes in GC", "/Devices/VNet%d/IO/WriteGC", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatIOWriteHC, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling IO writes in HC", "/Devices/VNet%d/IO/WriteHC", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatIntsRaised, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Number of raised interrupts", "/Devices/VNet%d/Interrupts/Raised", iInstance);
#endif /* VBOX_WITH_STATISTICS */
return rc;
}
/**
* Destruct PCI-related part of device.
*
* We need to free non-VM resources only.
*
* @returns VBox status.
* @param pState The device state structure.
*/
{
{
}
return VINF_SUCCESS;
}
/**
* Device relocation callback.
*
* When this callback is called the device instance data, and if the
* have been changed. The device must use the chance to perform the
* necessary pointer relocations and data updates.
*
* Before the GC code is executed the first time, this function will be
* called with a 0 delta so GC pointer calculations can be one in one place.
*
* @param pDevIns Pointer to the device instance.
* @param offDelta The relocation delta relative to the old location.
*
* @remark A relocation CANNOT fail.
*/
{
// TBD
}
{
/* Find an empty queue slot */
{
{
break;
}
}
if (!pQueue)
{
}
else
{
pQueue->uPageNumber = 0;
}
return pQueue;
}
#endif /* IN_RING3 */
//------------------------- Tear off here: vnet -------------------------------
/* Virtio net features */
#define NET_S_LINK_UP 1
#ifdef _MSC_VER
struct VNetPCIConfig
#else /* !_MSC_VER */
#endif /* !_MSC_VER */
{
};
/**
* Device state structure. Holds the current state of device.
*/
struct VNetState_st
{
/* VPCISTATE must be the first member! */
/** PCI config area holding MAC address as well as TBD. */
struct VNetPCIConfig config;
/** True if physical cable is attached in configuration. */
bool fCableConnected;
/** Locked state -- no state alteration possible. */
bool fLocked;
/* Receive-blocking-related fields ***************************************/
/** N/A: */
bool volatile fMaybeOutOfSpace;
/** EMT: Gets signalled when more RX descriptors become available. */
/* Statistic fields ******************************************************/
#if defined(VBOX_WITH_STATISTICS)
#endif /* VBOX_WITH_STATISTICS */
};
typedef struct VNetState_st VNETSTATE;
#define IFACE_TO_STATE(pIface, ifaceName) ((VNETSTATE *)((char*)pIface - RT_OFFSETOF(VNETSTATE, ifaceName)))
{
// TODO: implement
return NET_F_MAC | NET_F_STATUS;
}
{
{
Log(("%s vnetGetConfig: Read beyond the config structure is attempted (port=%RTiop cb=%x).\n", INSTANCE(pState), port, cb));
return VERR_INTERNAL_ERROR;
}
return VINF_SUCCESS;
}
{
{
Log(("%s vnetGetConfig: Write beyond the config structure is attempted (port=%RTiop cb=%x).\n", INSTANCE(pState), port, cb));
return VERR_INTERNAL_ERROR;
}
return VINF_SUCCESS;
}
/**
* Hardware reset. Revert all registers to initial values.
*
* @param pState The device state structure.
*/
{
// TODO: Implement reset
}
#ifdef IN_RING3
/**
* Wakeup the RX thread.
*/
{
if ( pState->fMaybeOutOfSpace
{
}
}
/**
* Link Up Timer handler.
*
* @param pDevIns Pointer to device instance structure.
* @param pTimer Pointer to the timer.
* @param pvUser NULL.
* @thread EMT
*/
{
STATUS |= NET_S_LINK_UP;
}
/**
* Handler for the wakeup signaller queue.
*/
{
return true;
}
#endif /* IN_RING3 */
#ifdef IN_RING3
/**
* Check if the device can receive data now.
* This must be called before the pfnRecieve() method is called.
*
* @returns Number of bytes the device can receive.
* @param pInterface Pointer to the interface structure containing the called function pointer.
* @thread EMT
*/
{
cb = 0; // TODO
}
{
if (RT_SUCCESS(rc))
return VINF_SUCCESS;
if (RT_UNLIKELY(cMillies == 0))
return VERR_NET_NO_BUFFER_SPACE;
{
if (RT_SUCCESS(rc2))
{
rc = VINF_SUCCESS;
break;
}
Log(("%s vnetWaitReceiveAvail: waiting cMillies=%u...\n",
}
return rc;
}
/**
* Provides interfaces to the driver.
*
* @returns Pointer to interface. NULL if the interface is not supported.
* @param pInterface Pointer to this interface structure.
* @param enmInterface The requested interface identification.
* @thread EMT
*/
static DECLCALLBACK(void *) vnetQueryInterface(struct PDMIBASE *pInterface, PDMINTERFACE enmInterface)
{
switch (enmInterface)
{
return &pState->INetworkPort;
return &pState->INetworkConfig;
default:
}
}
/**
* Receive data from the network.
*
* @returns VBox status code.
* @param pInterface Pointer to the interface structure containing the called function pointer.
* @param pvBuf The available data.
* @param cb Number of bytes available in the buffer.
* @thread ???
*/
{
int rc = VINF_SUCCESS;
// TODO: Implement
return rc;
}
/**
* Gets the current Media Access Control (MAC) address.
*
* @returns VBox status code.
* @param pInterface Pointer to the interface structure containing the called function pointer.
* @param pMac Where to store the MAC address.
* @thread EMT
*/
{
return VINF_SUCCESS;
}
/**
* Gets the new link state.
*
* @returns The current link state.
* @param pInterface Pointer to the interface structure containing the called function pointer.
* @thread EMT
*/
{
if (STATUS & NET_S_LINK_UP)
return PDMNETWORKLINKSTATE_UP;
return PDMNETWORKLINKSTATE_DOWN;
}
/**
* Sets the new link state.
*
* @returns VBox status code.
* @param pInterface Pointer to the interface structure containing the called function pointer.
* @param enmState The new link state
*/
static DECLCALLBACK(int) vnetSetLinkState(PPDMINETWORKCONFIG pInterface, PDMNETWORKLINKSTATE enmState)
{
{
if (fNewUp)
{
STATUS |= NET_S_LINK_UP;
}
else
{
STATUS &= ~NET_S_LINK_UP;
}
}
return VINF_SUCCESS;
}
{
}
{
}
{
}
/**
* Construct a device instance for a VM.
*
* @returns VBox status.
* @param pDevIns The device instance data.
* If the registration structure is needed, pDevIns->pDevReg points to it.
* @param iInstance Instance number. Use this to figure out which registers and such to use.
* The device number is also found in pDevIns->iInstance, but since it's
* likely to be freqently used PDM passes it as parameter.
* @param pCfgHandle Configuration node handle for the device. Use this to obtain the configuration
* of the device instance. It's also found in pDevIns->pCfgHandle, but like
* iInstance it's expected to be used a bit in this function.
* @thread EMT
*/
{
int rc;
/* Initialize PCI part first. */
/*
* Validate configuration.
*/
N_("Invalid configuraton for VirtioNet device"));
/* Get config params */
if (RT_FAILURE(rc))
N_("Configuration error: Failed to get MAC address"));
if (RT_FAILURE(rc))
N_("Configuration error: Failed to get the value of 'CableConnected'"));
/* Initialize state structure */
/* Interfaces */
// TODO:
/*
rc = PDMDevHlpSSMRegisterEx(pDevIns, VNET_SAVEDSTATE_VERSION, sizeof(VNETSTATE), NULL,
NULL, NULL, NULL,
NULL, vnetSaveExec, NULL,
NULL, vnetLoadExec, vnetLoadDone);
if (RT_FAILURE(rc))
return rc;*/
/* Create the RX notifier signaller. */
if (RT_FAILURE(rc))
return rc;
/* Create Link Up Timer */
TMTIMER_FLAGS_DEFAULT_CRIT_SECT, /** @todo check locking here. */
if (RT_FAILURE(rc))
return rc;
if (RT_SUCCESS(rc))
{
if (rc == VINF_NAT_DNS)
{
N_("A Domain Name Server (DNS) for NAT networking could not be determined. Ensure that your host is correctly connected to an ISP. If you ignore this warning the guest will not be able to perform nameserver lookups and it will probably observe delays if trying so"));
}
{
AssertMsgFailed(("%s Failed to obtain the PDMINTERFACE_NETWORK_CONNECTOR interface!\n"));
return VERR_PDM_MISSING_INTERFACE_BELOW;
}
}
else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
{
}
else
if (RT_FAILURE(rc))
return rc;
PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatReceiveBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data received", "/Devices/VNet%d/ReceiveBytes", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatTransmitBytes, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_BYTES, "Amount of data transmitted", "/Devices/VNet%d/TransmitBytes", iInstance);
#if defined(VBOX_WITH_STATISTICS)
PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatReceive, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling receive", "/Devices/VNet%d/Receive/Total", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatRxOverflow, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_OCCURENCE, "Profiling RX overflows", "/Devices/VNet%d/RxOverflow", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatRxOverflowWakeup, STAMTYPE_COUNTER, STAMVISIBILITY_ALWAYS, STAMUNIT_OCCURENCES, "Nr of RX overflow wakeups", "/Devices/VNet%d/RxOverflowWakeup", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatTransmit, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling transmits in HC", "/Devices/VNet%d/Transmit/Total", iInstance);
PDMDevHlpSTAMRegisterF(pDevIns, &pState->StatTransmitSend, STAMTYPE_PROFILE, STAMVISIBILITY_ALWAYS, STAMUNIT_TICKS_PER_CALL, "Profiling send transmit in HC", "/Devices/VNet%d/Transmit/Send", iInstance);
#endif /* VBOX_WITH_STATISTICS */
return VINF_SUCCESS;
}
/**
* Destruct a device instance.
*
* We need to free non-VM resources only.
*
* @returns VBox status.
* @param pDevIns The device instance data.
* @thread EMT
*/
{
{
}
}
/**
* Device relocation callback.
*
* When this callback is called the device instance data, and if the
* have been changed. The device must use the chance to perform the
* necessary pointer relocations and data updates.
*
* Before the GC code is executed the first time, this function will be
* called with a 0 delta so GC pointer calculations can be one in one place.
*
* @param pDevIns Pointer to the device instance.
* @param offDelta The relocation delta relative to the old location.
*
* @remark A relocation CANNOT fail.
*/
{
// TBD
}
/**
* @copydoc FNPDMDEVSUSPEND
*/
{
/* Poke thread waiting for buffer space. */
}
#ifdef VBOX_DYNAMIC_NET_ATTACH
/**
* Detach notification.
*
* One port on the network card has been disconnected from the network.
*
* @param pDevIns The device instance.
* @param iLUN The logical unit which is being detached.
* @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
*/
{
AssertLogRelReturnVoid(iLUN == 0);
/*
* Zero some important members.
*/
}
/**
* Attach the Network attachment.
*
* One port on the network card has been connected to a network.
*
* @returns VBox status code.
* @param pDevIns The device instance.
* @param iLUN The logical unit which is being attached.
* @param fFlags Flags, combination of the PDMDEVATT_FLAGS_* \#defines.
*
* @remarks This code path is not used during construction.
*/
{
/*
* Attach the driver.
*/
if (RT_SUCCESS(rc))
{
if (rc == VINF_NAT_DNS)
{
#ifdef RT_OS_LINUX
N_("A Domain Name Server (DNS) for NAT networking could not be determined. Please check your /etc/resolv.conf for <tt>nameserver</tt> entries. Either add one manually (<i>man resolv.conf</i>) or ensure that your host is correctly connected to an ISP. If you ignore this warning the guest will not be able to perform nameserver lookups and it will probably observe delays if trying so"));
#else
N_("A Domain Name Server (DNS) for NAT networking could not be determined. Ensure that your host is correctly connected to an ISP. If you ignore this warning the guest will not be able to perform nameserver lookups and it will probably observe delays if trying so"));
#endif
}
pState->pDrv = (PPDMINETWORKCONNECTOR)pState->pDrvBase->pfnQueryInterface(pState->pDrvBase, PDMINTERFACE_NETWORK_CONNECTOR);
{
AssertMsgFailed(("Failed to obtain the PDMINTERFACE_NETWORK_CONNECTOR interface!\n"));
}
}
else if (rc == VERR_PDM_NO_ATTACHED_DRIVER)
/*
* Temporary set the link down if it was up so that the guest
* will know that we have change the configuration of the
* network card
*/
{
STATUS &= ~NET_S_LINK_UP;
/* Restore the link back in 5 seconds. */
}
return rc;
}
#endif /* VBOX_DYNAMIC_NET_ATTACH */
/**
* @copydoc FNPDMDEVPOWEROFF
*/
{
/* Poke thread waiting for buffer space. */
}
/**
* The device registration structure.
*/
const PDMDEVREG g_DeviceVirtioNet =
{
/* Structure version. PDM_DEVREG_VERSION defines the current version. */
/* Device name. */
"virtio-net",
/* Name of guest context module (no path).
* Only evalutated if PDM_DEVREG_FLAGS_RC is set. */
"VBoxDDGC.gc",
/* Name of ring-0 module (no path).
* Only evalutated if PDM_DEVREG_FLAGS_RC is set. */
"VBoxDDR0.r0",
/* The description of the device. The UTF-8 string pointed to shall, like this structure,
* remain unchanged from registration till VM destruction. */
"Virtio Ethernet.\n",
/* Flags, combination of the PDM_DEVREG_FLAGS_* \#defines. */
PDM_DEVREG_FLAGS_DEFAULT_BITS, // | PDM_DEVREG_FLAGS_RC | PDM_DEVREG_FLAGS_R0,
/* Device class(es), combination of the PDM_DEVREG_CLASS_* \#defines. */
/* Maximum number of instances (per VM). */
8,
/* Size of the instance data. */
sizeof(VNETSTATE),
/* Construct instance - required. */
/* Destruct instance - optional. */
/* Relocation command - optional. */
/* I/O Control interface - optional. */
NULL,
/* Power on notification - optional. */
NULL,
/* Reset notification - optional. */
NULL,
/* Suspend notification - optional. */
/* Resume notification - optional. */
NULL,
#ifdef VBOX_DYNAMIC_NET_ATTACH
/* Attach command - optional. */
/* Detach notification - optional. */
#else /* !VBOX_DYNAMIC_NET_ATTACH */
/* Attach command - optional. */
NULL,
/* Detach notification - optional. */
NULL,
#endif /* !VBOX_DYNAMIC_NET_ATTACH */
/* Query a LUN base interface - optional. */
NULL,
/* Init complete notification - optional. */
NULL,
/* Power off notification - optional. */
/* pfnSoftReset */
NULL,
/* u32VersionEnd */
};
#endif /* IN_RING3 */
#endif /* !VBOX_DEVICE_STRUCT_TESTCASE */