VBoxNetFltCmn-win.h revision 7e9ca60730092c625220814121c54a593ad20997
/* $Id$ */
/** @file
* VBoxNetFltCmn-win.h - Bridged Networking Driver, Windows Specific Code.
* Common header with configuration defines and global defs
*/
/*
* Copyright (C) 2011 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.
*/
#ifndef ___VBoxNetFltCmn_win_h___
#define ___VBoxNetFltCmn_win_h___
#define LOG_GROUP LOG_GROUP_NET_FLT_DRV
/* debugging flags */
#ifdef DEBUG
//# define DEBUG_NETFLT_PACKETS
# ifndef DEBUG_misha
# define RT_NO_STRICT
# endif
/* # define DEBUG_NETFLT_LOOPBACK */
/* receive logic has several branches */
/* the DEBUG_NETFLT_RECV* macros used to debug the ProtocolReceive callback
* which is typically not used in case the underlying miniport indicates the packets with NdisMIndicateReceivePacket
* the best way to debug the ProtocolReceive (which in turn has several branches) is to enable the DEBUG_NETFLT_RECV
* one by one in the below order, i.e.
* first DEBUG_NETFLT_RECV
* then DEBUG_NETFLT_RECV + DEBUG_NETFLT_RECV_NOPACKET */
//# define DEBUG_NETFLT_RECV
//# define DEBUG_NETFLT_RECV_NOPACKET
//# define DEBUG_NETFLT_RECV_TRANSFERDATA
/* use ExAllocatePoolWithTag instead of NdisAllocateMemoryWithTag */
// #define DEBUG_NETFLT_USE_EXALLOC
#endif
#include <iprt/initterm.h>
#include <iprt/spinlock.h>
#include <iprt/semaphore.h>
/* ntddk.h has a missing #pragma pack(), work around it
* see #ifdef VBOX_WITH_WORKAROUND_MISSING_PACK below for detail */
# endif
# include <ntddk.h>
# pragma warning(default : 4163)
# pragma pack()
# pragma warning(default : 4103)
# endif
# include <ndis.h>
#else
//# include <ntddk.h>
/* can include ndis.h right away */
# include <ndis.h>
#endif
#define VBOXNETFLT_OS_SPECFIC 1
/** version
* NOTE: we are NOT using NDIS 5.1 features now */
#ifdef NDIS51_MINIPORT
# define VBOXNETFLT_VERSION_MP_NDIS_MAJOR 5
# define VBOXNETFLT_VERSION_MP_NDIS_MINOR 1
#else
# define VBOXNETFLT_VERSION_MP_NDIS_MAJOR 5
# define VBOXNETFLT_VERSION_MP_NDIS_MINOR 0
#endif
#ifndef VBOXNETADP
#ifdef NDIS51
# define VBOXNETFLT_VERSION_PT_NDIS_MAJOR 5
#else
# define VBOXNETFLT_VERSION_PT_NDIS_MAJOR 5
# define VBOXNETFLT_VERSION_PT_NDIS_MINOR 0
#endif
# define VBOXNETFLT_NAME_PROTOCOL L"VBoxNetFlt"
/** device to be used to prevent the driver unload & ioctl interface (if necessary in the future) */
# define VBOXNETFLT_NAME_LINK L"\\DosDevices\\Global\\VBoxNetFlt"
# define VBOXNETFLT_NAME_DEVICE L"\\Device\\VBoxNetFlt"
#else
# define VBOXNETFLT_NAME_LINK L"\\DosDevices\\Global\\VBoxNetAdp"
# define VBOXNETFLT_NAME_DEVICE L"\\Device\\VBoxNetAdp"
#endif
typedef struct VBOXNETFLTINS *PVBOXNETFLTINS;
/** configuration */
/** Ndis Packet pool settings
* these are applied to both receive and send packet pools */
/* number of packets for normal used */
#define VBOXNETFLT_PACKET_POOL_SIZE_NORMAL 0x000000FF
/* number of additional overflow packets */
#define VBOXNETFLT_PACKET_POOL_SIZE_OVERFLOW 0x0000FF00
/** packet queue size used when the driver is working in the "active" mode */
#define VBOXNETFLT_PACKET_INFO_POOL_SIZE 0x0000FFFF
#ifndef VBOXNETADP
/** memory tag used for memory allocations
* (VBNF stands for VBox NetFlt) */
# define VBOXNETFLT_MEM_TAG 'FNBV'
#else
/** memory tag used for memory allocations
* (VBNA stands for VBox NetAdp) */
# define VBOXNETFLT_MEM_TAG 'ANBV'
#endif
/** receive and transmit Ndis buffer pool size */
#define VBOXNETFLT_BUFFER_POOL_SIZE_TX 128
#define VBOXNETFLT_BUFFER_POOL_SIZE_RX 128
#define VBOXNETFLT_PACKET_ETHEADER_SIZE 14
#define VBOXNETFLT_PACKET_HEADER_MATCH_SIZE 24
#define VBOXNETFLT_PACKET_QUEUE_SG_SEGS_ALLOC 32
#if defined(DEBUG_NETFLT_PACKETS) || !defined(VBOX_LOOPBACK_USEFLAGS)
#endif
#ifdef VBOXNETADP
#define VBOXNETADP_HEADER_SIZE 14
#define VBOXNETADP_MAX_DATA_SIZE 1500
#define VBOXNETADP_MIN_PACKET_SIZE 60
/* link speed 100Mbps (measured in 100 bps) */
#define VBOXNETADP_LINK_SPEED 1000000
#define VBOXNETADP_VENDOR_ID 0x080027
#define VBOXNETADP_VENDOR_DRIVER_VERSION 0x00010000
#define VBOXNETADP_VENDOR_DESC "Sun"
#define VBOXNETADP_MAX_MCAST_LIST 32
#define VBOXNETADP_ETH_ADDRESS_LENGTH 6
//#define VBOXNETADP_REPORT_DISCONNECTED
#endif
/* type defs */
/** Flag specifying that the type of enqueued packet
* if set the info contains the PINTNETSG packet
* if clear the packet info contains the PNDIS_PACKET packet
* Typically the packet queue we are maintaining contains PNDIS_PACKETs only,
* however in case the underlying miniport indicates a packet with the NDIS_STATUS_RESOURCES status
* we MUST return the packet back to the miniport immediately
* this is why we are creating the INTNETSG, copying the ndis packet info there and enqueueing it */
#define VBOXNETFLT_PACKET_SG 0x00000001
/** the flag specifying that the packet source
* if set the packet comes from the host (upperlying protocol)
* if clear the packet comes from the wire (underlying miniport) */
#define VBOXNETFLT_PACKET_SRC_HOST 0x00000002
#ifndef VBOXNETFLT_NO_PACKET_QUEUE
/** flag specifying the packet was originated by our driver
* i.e. we could use it on our needs and should not return it
* we are enqueueing "our" packets on ProtocolReceive call-back when
* Ndis does not give us a receive packet (the driver below us has called NdisM..IndicateReceive)
* this is supported for Ndis Packet only */
#define VBOXNETFLT_PACKET_MINE 0x00000004
/** flag passed to vboxNetFltWinQuEnqueuePacket specifying that the packet should be copied
* this is supported for Ndis Packet only */
#define VBOXNETFLT_PACKET_COPY 0x00000008
#endif
/** packet queue element containing the packet info */
typedef struct VBOXNETFLT_PACKET_INFO
{
/** list entry used for enqueueing the info */
/** pointer to the pool containing this packet info */
struct VBOXNETFLT_PACKET_INFO_POOL *pPool;
/** flags describing the referenced packet. Contains PACKET_xxx flags (i.e. PACKET_SG, PACKET_SRC_HOST) */
/** pointer to the packet this info represents */
/* paranoid check to make sure the elements in the packet info array are properly aligned */
/** represents the packet queue */
/*
* we are using non-interlocked versions of LIST_ENTRY-related operations macros and synchronize
* access to the queue and its elements by acquiring/releasing a spinlock using Ndis[Acquire,Release]Spinlock
*
* we are NOT using interlocked versions of insert/remove head/tail list functions because we need to iterate though
* the queue elements as well as remove elements from the midle of the queue
*
* * @todo: it seems that we can switch to using interlocked versions of list-entry functions
* since we have removed all functionality (mentioned above, i.e. queue elements iteration, etc.) that might prevent us from doing this
*/
typedef struct VBOXNETFLT_INTERLOCKED_PACKET_QUEUE
{
/** queue */
/** queue lock */
typedef struct VBOXNETFLT_SINGLE_LIST
{
/** queue */
/** pointer to the list tail. used to enqueue elements to the tail of the list */
typedef struct VBOXNETFLT_INTERLOCKED_SINGLE_LIST
{
/** queue */
/** queue lock */
/** packet info pool contains free packet info elements to be used for the packet queue
* we are using the pool mechanism to allocate packet queue elements
* the pool mechanism is pretty simple now, we are allocating a bunch of memory
* for maintaining VBOXNETFLT_PACKET_INFO_POOL_SIZE queue elements and just returning null when the pool is exhausted
* This mechanism seems to be enough for now since we are using VBOXNETFLT_PACKET_INFO_POOL_SIZE = 0xffff which is
* the maximum size of packets the ndis packet pool supports */
typedef struct VBOXNETFLT_PACKET_INFO_POOL
{
/** free packet info queue */
/** memory bugger used by the pool */
typedef enum VBOXNETDEVOPSTATE
{
typedef enum VBOXNETFLT_WINIFSTATE
{
/** The usual invalid state. */
/** Initialization. */
/** Connected fuly functional state */
/** Disconnecting */
/** Disconnected */
/** structure used to maintain the state and reference count of the miniport and protocol */
typedef struct VBOXNETFLT_WINIF_DEVICE
{
/** initialize state */
/** ndis power state */
/** reference count */
#define VBOXNDISREQUEST_INPROGRESS 1
#define VBOXNDISREQUEST_QUEUED 2
typedef struct VBOXNETFLTWIN_STATE
{
union
{
struct
{
};
};
{
return *((PVBOXNETFLTWIN_STATE)((void*)&fValue));
}
/* miniport layer globals */
typedef struct VBOXNETFLTGLOBALS_MP
{
/** our miniport handle */
/** ddis wrapper handle */
#ifndef VBOXNETADP
/* protocol layer globals */
typedef struct VBOXNETFLTGLOBALS_PT
{
/** our protocol handle */
#endif /* #ifndef VBOXNETADP */
typedef struct VBOXNETFLTGLOBALS_WIN
{
/** synch event used for device creation synchronization */
/** Device reference count */
int cDeviceRefs;
/** ndis device */
/** device object */
/* loopback flags */
/* ndis packet flags to disable packet loopback */
/* ndis packet flags specifying whether the packet is looped back */
/* Minport info */
#ifndef VBOXNETADP
/* Protocol info */
#endif
/** represents filter driver device context*/
typedef struct VBOXNETFLTWIN
{
/** handle used by miniport edge for ndis calls */
/** miniport edge state */
/** ndis packet pool used for receives */
/** ndis buffer pool used for receives */
/** driver bind adapter state. */
#ifndef VBOXNETADP
/* misc state flags */
/** handle used by protocol edge for ndis calls */
/** protocol edge state */
/** ndis packet pool used for receives */
/** ndis buffer pool used for receives */
/** used for maintaining the pending send packets for handling packet loopback */
/** used for serializing calls to the NdisRequest in the vboxNetFltWinSynchNdisRequest */
/** event used to synchronize with the Ndis Request completion in the vboxNetFltWinSynchNdisRequest */
/** status of the Ndis Request initiated by the vboxNetFltWinSynchNdisRequest */
NDIS_STATUS volatile SynchCompletionStatus;
/** pointer to the Ndis Request being executed by the vboxNetFltWinSynchNdisRequest */
PNDIS_REQUEST volatile pSynchRequest;
* Since ndis adapter open and close requests may complete asynchronously,
* the status field is being set by the completion call-back */
/** medium we are attached to */
/**
* Passdown request info
*/
/** ndis request we pass down to the miniport below */
/** Ndis pass down request bytes read or written original pointer */
/** Ndis pass down request bytes needed original pointer */
/** true if we should indicate the receive complete used by the ProtocolReceive mechanism.
* We need to indicate it only with the ProtocolReceive + NdisMEthIndicateReceive path.
* Note: we're using KeGetCurrentProcessorNumber, which is not entirely correct in case
* we're running on 64bit win7+, which can handle > 64 CPUs, however since KeGetCurrentProcessorNumber
* always returns the number < than the number of CPUs in the first group, we're guaranteed to have CPU index < 64
* @todo: use KeGetCurrentProcessorNumberEx for Win7+ 64 and dynamically extended array */
bool abIndicateRxComplete[64];
/** Pending transfer data packet queue (i.e. packets that were indicated as pending on NdisTransferData call */
/* mac options initialized on OID_GEN_MAC_OPTIONS */
/** our miniport devuice name */
/** synchronize with unbind with Miniport initialization */
/** media connect status that we indicated */
/** media connect status pending to indicate */
/** packet filter flags set by the upper protocols */
/** packet filter flags set by the upper protocols */
/** packet filter flags set by us */
#else
volatile ULONG cTxSuccess;
volatile ULONG cRxSuccess;
#endif
typedef struct VBOXNETFLT_PACKET_QUEUE_WORKER
{
/** this event is used to initiate a packet queue worker thread kill */
/** this event is used to notify a worker thread that the packets are added to the queue */
/** pointer to the packet queue worker thread object */
/** pointer to the SG used by the packet queue for IntNet receive notifications */
/** Packet queue */
/** Packet info pool, i.e. the pool for the packet queue elements */
/* protocol reserved data held in ndis packet */
typedef struct VBOXNETFLT_PKTRSVD_PT
{
/** original packet received from the upperlying protocol
* can be null if the packet was originated by intnet */
/** pointer to the buffer to be freed on send completion
* can be null if no buffer is to be freed */
#if !defined(VBOX_LOOPBACK_USEFLAGS) || defined(DEBUG_NETFLT_PACKETS)
/* true if the packet is from IntNet */
bool bFromIntNet;
#endif
/** miniport reserved data held in ndis packet */
typedef struct VBOXNETFLT_PKTRSVD_MP
{
/** original packet received from the underling miniport
* can be null if the packet was originated by intnet */
/** pointer to the buffer to be freed on receive completion
* can be null if no buffer is to be freed */
/** represents the data stored in the protocol reserved field of ndis packet on NdisTransferData processing */
typedef struct VBOXNETFLT_PKTRSVD_TRANSFERDATA_PT
{
/** next packet in a list */
/* packet buffer start */
/* VBOXNETFLT_PKTRSVD_TRANSFERDATA_PT should fit into PROTOCOL_RESERVED_SIZE_IN_PACKET because we use protocol reserved part
* of our miniport edge on transfer data processing for honding our own info */
/* this should fit in MiniportReserved */
/* we use RTAsmAtomic*U32 for those, make sure we're correct */
#define NDIS_FLAGS_SKIP_LOOPBACK_W2K 0x400
#include "../../VBoxNetFltInternal.h"
#include "VBoxNetFltRt-win.h"
#ifndef VBOXNETADP
# include "VBoxNetFltP-win.h"
#endif
#include "VBoxNetFltM-win.h"
#endif /* #ifndef ___VBoxNetFltCmn_win_h___ */