VBoxNetFltP-win.cpp revision c7814cf6e1240a519cbec0441e033d0e2470ed00
/* $Id$ */
/** @file
* VBoxNetFltP-win.cpp - Bridged Networking Driver, Windows Specific Code.
* Protocol edge
*/
/*
* Copyright (C) 2011-2012 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.
*/
#include "VBoxNetFltCmn-win.h"
#ifdef VBOXNETADP
# error "No protocol edge"
#endif
#define VBOXNETFLT_PT_STATUS_IS_FILTERED(_s) (\
(_s) == NDIS_STATUS_MEDIA_CONNECT \
|| (_s) == NDIS_STATUS_MEDIA_DISCONNECT \
)
/**
* performs binding to the given adapter
*/
DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtDoBinding(PVBOXNETFLTINS pThis, PNDIS_STRING pOurDeviceName, PNDIS_STRING pBindToDeviceName)
{
if (Status == NDIS_STATUS_SUCCESS)
{
{
/* Ethernet */
/* Wan */
};
0, /* IN UINT OpenOptions, (reserved, should be NULL) */
NULL /* IN PSTRING AddressingInformation OPTIONAL */
);
if (Status == NDIS_STATUS_PENDING)
{
}
if (Status == NDIS_STATUS_SUCCESS)
{
if (Status == NDIS_STATUS_SUCCESS)
{
return NDIS_STATUS_SUCCESS;
}
else
{
}
}
else
{
}
}
return Status;
}
{
if (Status == NDIS_STATUS_SUCCESS)
{
if (Status == NDIS_STATUS_SUCCESS)
{
}
}
}
static VOID vboxNetFltWinPtOpenAdapterComplete(IN NDIS_HANDLE hProtocolBindingContext, IN NDIS_STATUS Status, IN NDIS_STATUS OpenErrorStatus)
{
LogFlow(("==>"__FUNCTION__": pNetFlt (0x%p), Status (0x%x), OpenErrorStatus(0x%x)\n", pNetFlt, Status, OpenErrorStatus));
{
if (Status != NDIS_STATUS_SUCCESS)
}
else
LogFlow(("<=="__FUNCTION__": pNetFlt (0x%p), Status (0x%x), OpenErrorStatus(0x%x)\n", pNetFlt, Status, OpenErrorStatus));
}
{
/* wait for request to complete */
while (vboxNetFltWinAtomicUoReadWinState(pNetFlt->u.s.WinIf.StateFlags).fRequestInfo == VBOXNDISREQUEST_INPROGRESS)
{
}
/*
* If the below miniport is going to low power state, complete the queued request
*/
{
/* mark the request as InProgress before posting it to RequestComplete */
}
else
{
}
}
{
int cPPUsage;
if (!bOnUnbind)
{
}
/* check packet pool is empty */
/* for debugging only, ignore the err in release */
{
if (!bOnUnbind)
{
}
else
{
}
}
else
{
}
return Status;
}
{
}
static VOID vboxNetFltWinPtUnloadProtocol()
{
}
static VOID vboxNetFltWinPtCloseAdapterComplete(IN NDIS_HANDLE ProtocolBindingContext, IN NDIS_STATUS Status)
{
{
}
}
static VOID vboxNetFltWinPtResetComplete(IN NDIS_HANDLE hProtocolBindingContext, IN NDIS_STATUS Status)
{
/*
* should never be here
*/
Assert(0);
}
static NDIS_STATUS vboxNetFltWinPtHandleQueryInfoComplete(PVBOXNETFLTINS pNetFlt, NDIS_STATUS Status)
{
{
case OID_PNP_CAPABILITIES:
{
if (Status == NDIS_STATUS_SUCCESS)
{
{
PNDIS_PNP_CAPABILITIES pPnPCaps = (PNDIS_PNP_CAPABILITIES)(pRequest->DATA.QUERY_INFORMATION.InformationBuffer);
}
else
{
Assert(0);
}
}
break;
}
case OID_GEN_MAC_OPTIONS:
{
if (Status == NDIS_STATUS_SUCCESS)
{
{
#ifndef VBOX_LOOPBACK_USEFLAGS
/* clearing this flag tells ndis we'll handle loopback ourselves
* the ndis layer or nic driver below us would loopback packets as necessary */
#else
/* we have to catch loopbacks from the underlying driver, so no duplications will occur,
* just indicate NDIS to handle loopbacks for the packets coming from the protocol */
#endif
}
else
{
Assert(0);
}
}
break;
}
{
{
/* we're here _ONLY_ in the passthru mode */
Assert(pNetFlt->u.s.WinIf.StateFlags.fProcessingPacketFilter && !pNetFlt->u.s.WinIf.StateFlags.fPPFNetFlt);
if (pNetFlt->u.s.WinIf.StateFlags.fProcessingPacketFilter && !pNetFlt->u.s.WinIf.StateFlags.fPPFNetFlt)
{
}
if (Status == NDIS_STATUS_SUCCESS)
{
{
/* the filter request is issued below only in case netflt is not active,
* simply update the cache here */
/* cache the filter used by upper protocols */
pNetFlt->u.s.WinIf.fUpperProtocolSetFilter = *(PULONG)pRequest->DATA.QUERY_INFORMATION.InformationBuffer;
}
else
{
Assert(0);
}
}
}
break;
}
default:
break;
}
return Status;
}
{
{
{
{
{
{
if (Status == NDIS_STATUS_SUCCESS)
{
{
}
else
{
Assert(0);
}
}
}
else
{
if (Status == NDIS_STATUS_SUCCESS)
{
{
/* the request was issued when the netflt was not active, simply update the cache here */
pNetFlt->u.s.WinIf.fUpperProtocolSetFilter = *((PULONG)pRequest->DATA.SET_INFORMATION.InformationBuffer);
}
else
{
Assert(0);
}
}
}
}
#ifdef DEBUG_misha
else
{
Assert(0);
}
#endif
}
break;
}
default:
break;
}
return Status;
}
DECLHIDDEN(VOID) vboxNetFltWinPtRequestComplete(NDIS_HANDLE hContext, PNDIS_REQUEST pNdisRequest, NDIS_STATUS Status)
{
LogFlow(("==>"__FUNCTION__" : pNetFlt (0x%p), pNdisRequest (0x%p), Status (0x%x)\n", pNetFlt, pNdisRequest, Status));
if (pSynchRequest == pNdisRequest)
{
/* asynchronous completion of our sync request */
/*1.set the status */
/* 2. set event */
/* 3. return; */
LogFlow(("<=="__FUNCTION__" : pNetFlt (0x%p), pNdisRequest (0x%p), Status (0x%x)\n", pNetFlt, pNdisRequest, Status));
return;
}
switch (pNdisRequest->RequestType)
{
break;
break;
default:
Assert(0);
break;
}
LogFlow(("<=="__FUNCTION__" : pNetFlt (0x%p), pNdisRequest (0x%p), Status (0x%x)\n", pNetFlt, pNdisRequest, Status));
}
static VOID vboxNetFltWinPtStatus(IN NDIS_HANDLE hProtocolBindingContext, IN NDIS_STATUS GeneralStatus, IN PVOID pvStatusBuffer, IN UINT cbStatusBuffer)
{
{
{
}
}
else
{
)
{
}
}
}
{
{
}
}
static VOID vboxNetFltWinPtSendComplete(IN NDIS_HANDLE hProtocolBindingContext, IN PNDIS_PACKET pPacket, IN NDIS_STATUS Status)
{
LogFlow(("==>"__FUNCTION__": pNetFlt (0x%p), pPacket (0x%p), Status (0x%x)\n", pNetFlt, pPacket, Status));
#if defined(DEBUG_NETFLT_PACKETS) || !defined(VBOX_LOOPBACK_USEFLAGS)
/* @todo: for optimization we could check only for netflt-mode packets
* do it for all for now */
#endif
if (pOrigPacket)
{
/* the ptk was posted from the upperlying protocol */
}
else
{
* need to free packet buffers */
}
if (pBufToFree)
{
}
LogFlow(("<=="__FUNCTION__": pNetFlt (0x%p), pPacket (0x%p), Status (0x%x)\n", pNetFlt, pPacket, Status));
}
/**
* removes searches for the packet in the list and removes it if found
* @return true if the packet was found and removed, false - otherwise
*/
static bool vboxNetFltWinRemovePacketFromList(PVBOXNETFLT_INTERLOCKED_SINGLE_LIST pList, PNDIS_PACKET pPacket)
{
PVBOXNETFLT_PKTRSVD_TRANSFERDATA_PT pTDR = (PVBOXNETFLT_PKTRSVD_TRANSFERDATA_PT)pPacket->ProtocolReserved;
}
/**
* puts the packet to the tail of the list
*/
static void vboxNetFltWinPutPacketToList(PVBOXNETFLT_INTERLOCKED_SINGLE_LIST pList, PNDIS_PACKET pPacket, PNDIS_BUFFER pOrigBuffer)
{
PVBOXNETFLT_PKTRSVD_TRANSFERDATA_PT pTDR = (PVBOXNETFLT_PKTRSVD_TRANSFERDATA_PT)pPacket->ProtocolReserved;
}
static bool vboxNetFltWinPtTransferDataCompleteActive(PVBOXNETFLTINS pNetFltIf, PNDIS_PACKET pPacket, NDIS_STATUS Status)
{
return false;
do
{
/* data transfer was initiated when the netFlt was active
* the netFlt is still retained by us
* 1. check if loopback
* 2. enqueue packet
* 3. release netFlt */
if (Status == NDIS_STATUS_SUCCESS)
{
#ifdef VBOX_LOOPBACK_USEFLAGS
{
/* should not be here */
Assert(0);
}
#else
if (pLb)
{
#ifndef DEBUG_NETFLT_RECV_TRANSFERDATA
/* should not be here */
Assert(0);
#endif
if (!vboxNetFltWinLbIsFromIntNet(pLb))
{
/* the packet is not from int net, need to pass it up to the host */
/* dereference NetFlt, WinIf will be dereferenced on Packet return */
break;
}
}
#endif
else
{
/* 2. enqueue */
/* use the same packet info to put the packet in the processing packet queue */
NdisGetPacketFlags(pPacket) = 0;
# ifdef VBOXNETFLT_NO_PACKET_QUEUE
{
/* drop it */
vboxNetFltWinFreeSGNdisPacket(pPacket, true);
}
else
{
}
break;
# else
if (Status == NDIS_STATUS_SUCCESS)
{
break;
}
Assert(0);
# endif
}
}
else
{
Assert(0);
}
/* we are here because of error either in data transfer or in enqueueing the packet */
vboxNetFltWinFreeSGNdisPacket(pPacket, true);
} while (0);
return true;
}
{
LogFlow(("==>"__FUNCTION__": pNetFlt (0x%p), pPacket (0x%p), Status (0x%x), cbTransfered (%d)\n", pNetFlt, pPacket, Status, cbTransferred));
{
{
}
}
/* else - all processing is done with vboxNetFltWinPtTransferDataCompleteActive already */
LogFlow(("<=="__FUNCTION__": pNetFlt (0x%p), pPacket (0x%p), Status (0x%x), cbTransfered (%d)\n", pNetFlt, pPacket, Status, cbTransferred));
}
static INT vboxNetFltWinRecvPacketPassThru(PVBOXNETFLTINS pNetFlt, PNDIS_PACKET pPacket, BOOLEAN bForceIndicate)
{
/* the Status holds the current packet status it will be checked for NDIS_STATUS_RESOURCES later
* (see below) */
if (pMyPacket)
{
if (Status == NDIS_STATUS_RESOURCES)
{
return 0;
}
return 1;
}
return 0;
}
/**
* process the packet receive in a "passthru" mode
*/
{
if (Status == NDIS_STATUS_SUCCESS)
{
}
return Status;
}
static VOID vboxNetFltWinRecvIndicatePassThru(PVBOXNETFLTINS pNetFlt, NDIS_HANDLE MacReceiveContext,
PVOID pHeaderBuffer, UINT cbHeaderBuffer, PVOID pLookAheadBuffer, UINT cbLookAheadBuffer, UINT cbPacket)
{
/* 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 */
{
case NdisMedium802_3:
case NdisMediumWan:
cbPacket);
break;
default:
break;
}
}
/**
* process the ProtocolReceive in an "active" mode
*
* @return NDIS_STATUS_SUCCESS - the packet is processed
* NDIS_STATUS_PENDING - the packet is being processed, we are waiting for the ProtocolTransferDataComplete to be called
* NDIS_STATUS_NOT_ACCEPTED - the packet is not needed - typically this is because this is a loopback packet
* NDIS_STATUS_FAILURE - packet processing failed
*/
static NDIS_STATUS vboxNetFltWinPtReceiveActive(PVBOXNETFLTINS pNetFlt, NDIS_HANDLE MacReceiveContext, PVOID pHeaderBuffer, UINT cbHeaderBuffer,
{
do
{
{
break;
}
#ifndef DEBUG_NETFLT_RECV_TRANSFERDATA
if (cbPacket == cbLookaheadBuffer)
{
#ifndef VBOX_LOOPBACK_USEFLAGS
#endif
/* allocate SG buffer */
if (Status != NDIS_STATUS_SUCCESS)
{
Assert(0);
break;
}
#ifndef VBOX_LOOPBACK_USEFLAGS
if (pLb)
{
#ifndef DEBUG_NETFLT_RECV_NOPACKET
/* should not be here */
Assert(0);
#endif
if (!vboxNetFltWinLbIsFromIntNet(pLb))
{
pSG, /* PINTNETSG */
pSG, /* PVOID pBufToFree */
false, /* bool bToWire */
false); /* bool bCopyMemory */
if (pMyPacket)
{
/* dereference the NetFlt here & indicate SUCCESS, which would mean the caller would not do a dereference
* the WinIf dereference will be done on packet return */
}
else
{
}
}
else
{
}
break;
}
#endif
/* enqueue SG */
# ifdef VBOXNETFLT_NO_PACKET_QUEUE
{
/* drop it */
}
else
{
pSG, /* PINTNETSG */
pSG, /* PVOID pBufToFree */
false, /* bool bToWire */
false); /* bool bCopyMemory */
if (pMyPacket)
{
}
else
{
}
}
# else
if (Status != NDIS_STATUS_SUCCESS)
{
Assert(0);
break;
}
# endif
#endif
}
else
{
/* allocate NDIS Packet buffer */
if (Status != NDIS_STATUS_SUCCESS)
{
Assert(0);
break;
}
#ifdef VBOX_LOOPBACK_USEFLAGS
/* set "don't loopback" flags */
#else
NdisGetPacketFlags(pPacket) = 0;
#endif
if (Status != NDIS_STATUS_SUCCESS)
{
Assert(0);
break;
}
NdisAllocateBuffer(&Status, &pTransferBuffer, pNetFlt->u.s.WinIf.hRecvBufferPool, pMemBuf + cbHeaderBuffer, cbPacket);
if (Status != NDIS_STATUS_SUCCESS)
{
Assert(0);
break;
}
if (Status != NDIS_STATUS_SUCCESS)
{
Assert(0);
break;
}
if (cbPacket == cbLookaheadBuffer)
{
}
else
#endif
{
0, /* ByteOffset */
}
if (Status != NDIS_STATUS_PENDING)
{
}
}
} while (0);
return Status;
}
{
bool bNetFltActive;
const bool bPassThruActive = !bNetFltActive;
if (fWinIfActive)
{
do
{
#ifndef DEBUG_NETFLT_RECV_NOPACKET
if (pPacket)
{
# ifndef VBOX_LOOPBACK_USEFLAGS
# else
{
Assert(0);
/* nothing else to do here, just return the packet */
//NdisReturnPackets(&pPacket, 1);
break;
}
# endif
if (bNetFltActive)
{
# ifndef VBOX_LOOPBACK_USEFLAGS
if (!pLb)
# endif
{
# ifdef VBOXNETFLT_NO_PACKET_QUEUE
{
/* drop it */
break;
}
# else
if (Status == NDIS_STATUS_SUCCESS)
{
//NdisReturnPackets(&pPacket, 1);
fWinIfActive = false;
bNetFltActive = false;
break;
}
# endif
}
# ifndef VBOX_LOOPBACK_USEFLAGS
else if (vboxNetFltWinLbIsFromIntNet(pLb))
{
/* nothing else to do here, just return the packet */
//NdisReturnPackets(&pPacket, 1);
break;
}
/* we are here because this is a looped back packet set not from intnet
* we will post it to the upper protocol */
# endif
}
if (Status == STATUS_SUCCESS)
{
# ifndef VBOX_LOOPBACK_USEFLAGS
# endif
/* we are done with packet processing, and we will
* not receive packet return event for this packet,
* fWinIfActive should be true to ensure we release WinIf*/
if (Status == STATUS_SUCCESS)
break;
}
else
{
/* intnet processing failed - fall back to no-packet mode */
}
}
#endif /* #ifndef DEBUG_NETFLT_RECV_NOPACKET */
if (bNetFltActive)
{
if (NT_SUCCESS(Status))
{
if (Status != NDIS_STATUS_NOT_ACCEPTED)
{
fWinIfActive = false;
bNetFltActive = false;
}
else
{
#ifndef VBOX_LOOPBACK_USEFLAGS
/* this is a loopback packet, nothing to do here */
#else
Assert(0);
/* should not be here */
#endif
}
break;
}
}
/* we are done with packet processing, and we will
* not receive packet return event for this packet,
* fWinIfActive should be true to ensure we release WinIf*/
vboxNetFltWinRecvIndicatePassThru(pNetFlt, MacReceiveContext, pHeaderBuffer, cbHeaderBuffer, pLookAheadBuffer, cbLookAheadBuffer, cbPacket);
/* the status could contain an error value here in case the IntNet recv failed,
* ensure we return back success status */
} while (0);
if (bNetFltActive)
{
}
else if (bPassThruActive)
{
}
if (fWinIfActive)
{
}
}
else
{
}
return Status;
}
{
bool bNetFltActive;
/* 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 */
{
{
case NdisMedium802_3:
case NdisMediumWan:
break;
default:
Assert(0);
break;
}
}
if (fWinIfActive)
{
if (bNetFltActive)
{
}
else
{
}
}
}
{
bool bNetFltActive;
const bool bPassThruActive = !bNetFltActive;
if (fWinIfActive)
{
do
{
#ifdef VBOX_LOOPBACK_USEFLAGS
{
Assert(0);
Log(("lb_rp"));
/* nothing else to do here, just return the packet */
cRefCount = 0;
//NdisReturnPackets(&pPacket, 1);
break;
}
#endif
if (bNetFltActive)
{
#ifndef VBOX_LOOPBACK_USEFLAGS
if (!pLb)
#endif
{
#ifndef VBOXNETFLT_NO_PACKET_QUEUE
#endif
#ifdef DEBUG_misha
/*TODO: remove this assert.
* this is a temporary assert for debugging purposes:
* we're probably doing something wrong with the packets if the miniport reports NDIS_STATUS_RESOURCES */
Assert(!bResources);
#endif
#ifdef VBOXNETFLT_NO_PACKET_QUEUE
{
/* drop it */
cRefCount = 0;
break;
}
#else
if (fStatus == NDIS_STATUS_SUCCESS)
{
bNetFltActive = false;
fWinIfActive = false;
if (bResources)
{
cRefCount = 0;
//NdisReturnPackets(&pPacket, 1);
}
else
{
cRefCount = 1;
}
break;
}
else
{
Assert(0);
}
#endif
}
#ifndef VBOX_LOOPBACK_USEFLAGS
else if (vboxNetFltWinLbIsFromIntNet(pLb))
{
/* the packet is from intnet, it has already been set to the host,
* no need for loopng it back to the host again */
/* nothing else to do here, just return the packet */
cRefCount = 0;
//NdisReturnPackets(&pPacket, 1);
break;
}
#endif
}
if (cRefCount)
{
fWinIfActive = false;
}
} while (FALSE);
if (bNetFltActive)
{
}
else if (bPassThruActive)
{
}
if (fWinIfActive)
{
}
}
else
{
cRefCount = 0;
//NdisReturnPackets(&pPacket, 1);
}
return cRefCount;
}
{
{
Assert(0);
return false;
}
{
Assert(0);
return false;
}
if (*pStatus == NDIS_STATUS_PENDING)
{
}
return true;
}
static NDIS_STATUS vboxNetFltWinPtPnPSetPower(PVBOXNETFLTINS pNetFlt, NDIS_DEVICE_POWER_STATE enmPowerState)
{
NDIS_DEVICE_POWER_STATE enmPrevPowerState = vboxNetFltWinGetPowerState(&pNetFlt->u.s.WinIf.PtState);
{
if (enmPrevPowerState == NdisDeviceStateD0)
{
}
/* check packet pool is empty */
/* for debugging only, ignore the err in release */
}
else
{
{
}
{
}
else
{
}
}
return NDIS_STATUS_SUCCESS;
}
static NDIS_STATUS vboxNetFltWinPtPnPEvent(IN NDIS_HANDLE hProtocolBindingContext, IN PNET_PNP_EVENT pNetPnPEvent)
{
switch (pNetPnPEvent->NetEvent)
{
case NetEventSetPower:
{
}
case NetEventReconfigure:
{
if (!pNetFlt)
{
}
}
default:
return NDIS_STATUS_SUCCESS;
}
}
#ifdef __cplusplus
#else
#endif
/**
* register the protocol edge
*/
DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtRegister(PVBOXNETFLTGLOBALS_PT pGlobalsPt, PDRIVER_OBJECT pDriverObject, PUNICODE_STRING pRegistryPathStr)
{
#if !defined(DEBUG_NETFLT_RECV)
#endif
return Status;
}
/**
* deregister the protocol edge
*/
{
if (!pGlobalsPt->hProtocol)
return NDIS_STATUS_SUCCESS;
if (Status == NDIS_STATUS_SUCCESS)
{
}
return Status;
}