VBoxNetFltRt-win.cpp revision b47bb47439dd595c9715ef0b6874c89927ef3cbf
/* $Id$ */
/** @file
* VBoxNetFltRt-win.cpp - Bridged Networking Driver, Windows Specific Code.
* NetFlt Runtime
*/
/*
* 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.
*/
#include "VBoxNetFltCmn-win.h"
#include <VBox/intnetinline.h>
/** represents the job element of the job queue
* see comments for VBOXNETFLT_JOB_QUEUE */
typedef struct VBOXNETFLT_JOB
{
/** link in the job queue */
/** job function to be executed */
/** parameter to be passed to the job function */
/** event that will be fired on job completion */
/** true if the job manager should use the completion even for completion indication, false-otherwise*/
bool bUseCompletionEvent;
/**
* represents the queue of jobs processed by the worker thread
*
* we use the thread to process tasks which are required to be done at passive level
* our callbacks may be called at APC level by IntNet, there are some tasks that we can not create at APC,
* e.g. thread creation. This is why we schedule such jobs to the worker thread working at passive level
*/
typedef struct VBOXNETFLT_JOB_QUEUE
{
/* jobs */
/* we are using ExInterlocked..List functions to access the jobs list */
/** this event is used to initiate a job worker thread kill */
/** this event is used to notify a worker thread that jobs are added to the queue */
/** worker thread */
typedef struct _CREATE_INSTANCE_CONTEXT
{
#ifndef VBOXNETADP
#else
#endif
/*contexts used for our jobs */
/* Attach context */
typedef struct _ATTACH_INFO
{
bool fRediscovery;
int Status;
/* general worker context */
typedef struct _WORKER_INFO
{
int Status;
/* idc initialization */
typedef struct _INIT_IDC_INFO
{
bool bInitialized;
volatile bool bStop;
volatile int rc;
/** globals */
/** global job queue. some operations are required to be done at passive level, e.g. thread creation, adapter bind/unbind initiation,
* while IntNet typically calls us APC_LEVEL, so we just create a system thread in our DriverEntry and enqueue the jobs to that thread */
static VBOXNETFLT_JOB_QUEUE g_VBoxJobQueue;
volatile static bool g_bVBoxIdcInitialized;
/**
* The (common) global data.
*/
static VBOXNETFLTGLOBALS g_VBoxNetFltGlobals;
/* win-specific global data */
#define LIST_ENTRY_2_JOB(pListEntry) \
static int vboxNetFltWinAttachToInterface(PVBOXNETFLTINS pThis, void * pContext, bool fRediscovery);
static int vboxNetFltWinTryFiniIdc();
static void vboxNetFltWinFiniNetFltBase();
static int vboxNetFltWinInitNetFltBase();
static int vboxNetFltWinFiniNetFlt();
static int vboxNetFltWinStartInitIdcProbing();
static int vboxNetFltWinStopInitIdcProbing();
/** makes the current thread to sleep for the given number of miliseconds */
{
}
/** wait for the given device to be dereferenced */
{
#ifdef DEBUG
#endif
{
#ifdef DEBUG
{
LogRel(("device not idle"));
AssertFailed();
// break;
}
#endif
}
}
/**
* mem functions
*/
/* allocates and zeroes the nonpaged memory of a given size */
{
#ifdef DEBUG_NETFLT_USE_EXALLOC
if (*ppMemBuf)
{
return NDIS_STATUS_SUCCESS;
}
return NDIS_STATUS_FAILURE;
#else
if (fStatus == NDIS_STATUS_SUCCESS)
{
}
return fStatus;
#endif
}
/* frees memory allocated with vboxNetFltWinMemAlloc */
{
#ifdef DEBUG_NETFLT_USE_EXALLOC
#else
NdisFreeMemory(pvMemBuf, 0, 0);
#endif
}
#ifndef VBOXNETFLT_NO_PACKET_QUEUE
/* initializes packet info pool and allocates the cSize packet infos for the pool */
static NDIS_STATUS vboxNetFltWinPpAllocatePacketInfoPool(PVBOXNETFLT_PACKET_INFO_POOL pPool, UINT cSize)
{
UINT i;
if (fStatus == NDIS_STATUS_SUCCESS)
{
for (i = 0; i < cSize; i++)
{
pInfo = &pPacketInfos[i];
}
}
else
{
AssertFailed();
}
return fStatus;
}
/* frees the packet info pool */
{
}
#endif
/**
* copies one string to another. in case the destination string size is not enough to hold the complete source string
* does nothing and returns NDIS_STATUS_RESOURCES .
*/
{
{
{
AssertFailed();
}
else
{
{
}
}
}
return Status;
}
/************************************************************************************
* PINTNETSG pSG manipulation functions
************************************************************************************/
/* moves the contents of the given NDIS_BUFFER and all other buffers chained to it to the PINTNETSG
* the PINTNETSG is expected to contain one segment whose bugger is large enough to maintain
* the contents of the given NDIS_BUFFER and all other buffers chained to it */
{
while (pBuffer)
{
if (!pVirtualAddress)
{
break;
}
ptr += cbCurrentLength;
}
if (fStatus == NDIS_STATUS_SUCCESS)
{
}
return fStatus;
}
/* converts the PNDIS_BUFFER to PINTNETSG by making the PINTNETSG segments to point to the memory buffers the
* ndis buffer(s) point to (as opposed to vboxNetFltWinNdisBufferMoveToSG0 which copies the memory from ndis buffers(s) to PINTNETSG) */
{
while (pBuffer)
{
if (!pVirtualAddress)
{
break;
}
cSegs++;
}
if (Status == NDIS_STATUS_SUCCESS)
{
}
return Status;
}
{
}
{
if (Status == STATUS_SUCCESS)
{
return pSG;
}
return NULL;
}
/************************************************************************************
* packet queue functions
************************************************************************************/
#ifndef VBOXNETFLT_NO_PACKET_QUEUE
#if !defined(VBOXNETADP)
static NDIS_STATUS vboxNetFltWinQuPostPacket(PVBOXNETFLTINS pNetFlt, PNDIS_PACKET pPacket, PINTNETSG pSG, uint32_t fFlags
# ifdef DEBUG_NETFLT_PACKETS
# endif
)
{
LogFlow(("posting packet back to driver stack..\n"));
if (!pPacket)
{
/* INTNETSG was in the packet queue, create a new NdisPacket from INTNETSG*/
pSG, /* PINTNETSG */
pSG, /* PVOID pBufToFree */
bSrcHost, /* bool bToWire */
false); /* bool bCopyMemory */
#ifdef DEBUG_NETFLT_PACKETS
#endif
}
else
{
/* NDIS_PACKET was in the packet queue */
if (!(fFlags & PACKET_MINE))
{
* According to the DDK, we can not post it further,
* instead we should allocate our own packet.
* So, allocate our own packet (pMyPacket) and copy the packet info there */
if (bSrcHost)
{
}
else
{
}
}
else
{
/* the packet enqueued is ours, simply assign pMyPacket and zero pPacket */
}
}
if (pMyPacket)
{
/* we have successfully initialized our packet, post it to the host or to the wire */
if (bSrcHost)
{
#if defined(DEBUG_NETFLT_PACKETS) || !defined(VBOX_LOOPBACK_USEFLAGS)
#endif
if (Status != NDIS_STATUS_PENDING)
{
#if defined(DEBUG_NETFLT_PACKETS) || !defined(VBOX_LOOPBACK_USEFLAGS)
/* the status is NOT pending, complete the packet */
#endif
if (pPacket)
{
}
else
{
/* should never be here since the PINTNETSG is stored only when the underlying miniport
* indicates NDIS_STATUS_RESOURCES, we should never have this when processing
* the "from-host" packets */
AssertFailed();
vboxNetFltWinFreeSGNdisPacket(pMyPacket, false);
}
}
}
else
{
/* the packet receive completion is always indicated via MiniportReturnPacket */
}
}
else
{
/*we failed to create our packet */
AssertFailed();
}
return Status;
}
#endif
static bool vboxNetFltWinQuProcessInfo(PVBOXNETFLTINS pNetFltIf, PPACKET_QUEUE_WORKER pWorker, PVOID pvPacket, const UINT fFlags)
#else
DECLHIDDEN(bool) vboxNetFltWinPostIntnet(PVBOXNETFLTINS pNetFltIf, PVOID pvPacket, const UINT fFlags)
#endif
{
#ifndef VBOXNETADP
bool bSrcHost;
bool bDropIt;
# ifndef VBOXNETFLT_NO_PACKET_QUEUE
bool bPending;
# endif
#endif
#ifdef VBOXNETFLT_NO_PACKET_QUEUE
bool bDeleteSG = false;
#endif
#ifdef DEBUG_NETFLT_PACKETS
/* packet used for matching */
#endif
#ifndef VBOXNETADP
#endif
/* we first need to obtain the INTNETSG to be passed to intnet */
/* the queue may contain two "types" of packets:
* the NDIS_PACKET and the INTNETSG.
* however in case our ProtocolReceive is called or the packet's status is set to NDIS_STSTUS_RESOURCES
* in ProtocolReceivePacket, we must return the packet immediately on ProtocolReceive*** exit
* In this case we allocate the INTNETSG, copy the ndis packet data there and enqueue it.
* In this case the packet info flags has the VBOXNETFLT_PACKET_SG fag set
*
* Besides that the NDIS_PACKET contained in the queue could be either the one passed to us in our send/receive callback
* or the one created by us. The latter is possible in case our ProtocolReceive callback is called and we call NdisTransferData
* in this case we need to allocate the packet the data to be transferred to.
* If the enqueued packet is the one allocated by us the VBOXNETFLT_PACKET_MINE flag is set
* */
if ((fFlags & VBOXNETFLT_PACKET_SG) == 0)
{
/* we have NDIS_PACKET enqueued, we need to convert it to INTNETSG to be passed to intnet */
UINT uBytesCopied = 0;
LogFlow(("preparing pSG"));
#ifdef VBOXNETFLT_NO_PACKET_QUEUE
#else
/* we can not allocate the INTNETSG on stack since in this case we may get stack overflow
* somewhere outside of our driver (3 pages of system thread stack does not seem to be enough)
*
* since we have a "serialized" packet processing, i.e. all packets are being processed and passed
* to intnet by this thread, we just use one previously allocated INTNETSG which is stored in PVBOXNETFLTINS */
{
if (pSG)
{
}
else
{
LogRel(("Failed to reallocate the pSG\n"));
}
}
#endif
if (pSG)
{
#ifdef VBOXNETFLT_NO_PACKET_QUEUE
bDeleteSG = true;
#endif
/* reinitialize */
/* convert the ndis buffers to INTNETSG */
if (Status != NDIS_STATUS_SUCCESS)
{
}
else
{
}
}
}
else
{
* just use the INTNETSG to pass it to intnet */
#ifndef VBOXNETADP
/* the PINTNETSG is stored only when the underlying miniport
* indicates NDIS_STATUS_RESOURCES, we should never have this when processing
* the "from-host" packedts */
#endif
}
#ifdef DEBUG_NETFLT_PACKETS
if (!pPacket && !pTmpPacket)
{
/* create tmp packet that woud be used for matching */
pSG, /* PINTNETSG */
pSG, /* PVOID pBufToFree */
bSrcHost, /* bool bToWire */
true); /* bool bCopyMemory */
}
#endif
do
{
#ifndef VBOXNETADP
/* the pSG was successfully initialized, post it to the netFlt*/
)
: false;
#else
if (pSG)
{
}
else
{
}
#endif
#ifndef VBOXNETFLT_NO_PACKET_QUEUE
# if !defined(VBOXNETADP)
if (!bDropIt)
{
# ifdef DEBUG_NETFLT_PACKETS
# endif
);
if (Status == NDIS_STATUS_PENDING)
{
/* we will process packet completion in the completion routine */
bPending = true;
break;
}
}
else
# endif
{
}
/* drop it */
if (pPacket)
{
if (!(fFlags & PACKET_MINE))
{
# if !defined(VBOXNETADP)
/* complete the packets */
if (fFlags & PACKET_SRC_HOST)
{
# endif
/* NDIS_SET_PACKET_STATUS(pPacket, Status); */
# if !defined(VBOXNETADP)
}
else
{
# endif
# ifndef VBOXNETADP
# endif
# if !defined(VBOXNETADP)
}
# endif
}
else
{
vboxNetFltWinFreeSGNdisPacket(pPacket, true);
}
}
else
{
}
# ifndef VBOXNETADP
bPending = false;
# endif
} while (0);
#ifdef DEBUG_NETFLT_PACKETS
if (pTmpPacket)
{
}
#endif
#ifndef VBOXNETADP
return bPending;
#else
return false;
#endif
#else /* #ifdef VBOXNETFLT_NO_PACKET_QUEUE */
} while (0);
if (bDeleteSG)
# ifndef VBOXNETADP
return bDropIt;
# else
return true;
# endif
#endif
}
#ifndef VBOXNETFLT_NO_PACKET_QUEUE
/*
* thread start function for the thread which processes the packets enqueued in our send and receive callbacks called by ndis
*
* ndis calls us at DISPATCH_LEVEL, while IntNet is using kernel functions which require Irql<DISPATCH_LEVEL
* instead we put the incoming packets to the queue and maintain the system thread running at passive level
* which processes the queue and posts the packets to IntNet, and further to the host or to the wire.
*/
{
bool fResume = true;
};
while (fResume)
{
fStatus = KeWaitForMultipleObjects(RT_ELEMENTS(apEvents), apEvents, WaitAny, Executive, KernelMode, FALSE, NULL, NULL);
{
/* "kill" event was set
* will process queued packets and exit */
fResume = false;
}
LogFlow(("processing vboxNetFltWinQuPacketQueueWorkerThreadProc\n"));
cNumProcessed = 0;
cNumPostedToHostWire = 0;
do
{
#ifdef DEBUG_NETFLT_PACKETS
/* packet used for matching */
#endif
/*TODO: FIXME: !!! the better approach for performance would be to dequeue all packets at once
* and then go through all dequeued packets
* the same should be done for enqueue !!! */
if (!pInfo)
{
break;
}
{
}
} while (TRUE);
if (cNumProcessed)
{
if (cNumProcessed != cNumPostedToHostWire)
{
}
}
}
}
#endif
/**
* thread start function for the job processing thread
*
* see comments for PVBOXNETFLT_JOB_QUEUE
*/
{
bool fResume = true;
};
do
{
Status = KeWaitForMultipleObjects(RT_ELEMENTS(apEvents), apEvents, WaitAny, Executive, KernelMode, FALSE, NULL, NULL);
{
/* will process queued jobs and exit */
fResume = false;
}
do
{
if (!pJobEntry)
break;
if (pJob->bUseCompletionEvent)
{
}
} while (TRUE);
} while (fResume);
}
/**
* enqueues the job to the job queue to be processed by the job worker thread
* see comments for PVBOXNETFLT_JOB_QUEUE
*/
static VOID vboxNetFltWinJobEnqueueJob(PVBOXNETFLT_JOB_QUEUE pQueue, PVBOXNETFLT_JOB pJob, bool bEnqueueHead)
{
if (bEnqueueHead)
{
}
else
{
}
}
DECLINLINE(VOID) vboxNetFltWinJobInit(PVBOXNETFLT_JOB pJob, PFNVBOXNETFLT_JOB_ROUTINE pfnRoutine, PVOID pContext, bool bUseEvent)
{
if (bUseEvent)
}
/**
* enqueues the job to the job queue to be processed by the job worker thread and
* blocks until the job is done
* see comments for PVBOXNETFLT_JOB_QUEUE
*/
static VOID vboxNetFltWinJobSynchExec(PVBOXNETFLT_JOB_QUEUE pQueue, PFNVBOXNETFLT_JOB_ROUTINE pfnRoutine, PVOID pContext)
{
}
/**
* enqueues the job to be processed by the job worker thread at passive level and
* blocks until the job is done
*/
DECLHIDDEN(VOID) vboxNetFltWinJobSynchExecAtPassive(PFNVBOXNETFLT_JOB_ROUTINE pfnRoutine, PVOID pContext)
{
}
/**
* helper function used for system thread creation
*/
static NTSTATUS vboxNetFltWinQuCreateSystemThread(PKTHREAD *ppThread, PKSTART_ROUTINE pfnStartRoutine, PVOID pvStartContext)
{
NTSTATUS Status = PsCreateSystemThread(&hThread, THREAD_ALL_ACCESS, &ObjectAttributes, NULL, NULL, (PKSTART_ROUTINE)pfnStartRoutine, pvStartContext);
if (Status == STATUS_SUCCESS)
{
Status = ObReferenceObjectByHandle(hThread, THREAD_ALL_ACCESS, NULL, KernelMode, (PVOID*)ppThread, NULL);
if (Status == STATUS_SUCCESS)
{
return STATUS_SUCCESS;
}
/* @todo: how would we fail in this case ?*/
}
return Status;
}
/**
* initialize the job queue
* see comments for PVBOXNETFLT_JOB_QUEUE
*/
{
fStatus = vboxNetFltWinQuCreateSystemThread(&pQueue->pThread, (PKSTART_ROUTINE)vboxNetFltWinJobWorkerThreadProc, pQueue);
if (fStatus != STATUS_SUCCESS)
{
}
else
{
}
return fStatus;
}
/**
* deinitialize the job queue
* see comments for PVBOXNETFLT_JOB_QUEUE
*/
{
{
}
}
#ifndef VBOXNETFLT_NO_PACKET_QUEUE
/**
* initializes the packet queue
* */
{
do
{
Status = vboxNetFltWinPpAllocatePacketInfoPool(&pWorker->PacketInfoPool, VBOXNETFLT_PACKET_INFO_POOL_SIZE);
if (Status == NDIS_STATUS_SUCCESS)
{
{
break;
}
Status = vboxNetFltWinQuCreateSystemThread(&pWorker->pThread, (PKSTART_ROUTINE)vboxNetFltWinQuPacketQueueWorkerThreadProc, pInstance);
if (Status != STATUS_SUCCESS)
{
break;
}
}
} while (0);
return Status;
}
/*
* deletes the packet queue
*/
{
/* using the pPacketQueueSG as an indicator that the packet queue is initialized */
{
}
else
{
}
}
#endif
/*
* creates the INTNETSG containing one segment pointing to the buffer of size cbBufSize
* the INTNETSG created should be cleaned with vboxNetFltWinMemFree
*/
{
/* allocation:
* 1. SG_PACKET - with one aSegs pointing to
* 2. buffer of cbPacket containing the entire packet */
if (Status == NDIS_STATUS_SUCCESS)
{
}
return Status;
}
#ifndef VBOXNETFLT_NO_PACKET_QUEUE
/**
* put the packet info to the queue
*/
DECLINLINE(void) vboxNetFltWinQuEnqueueInfo(PVBOXNETFLTPACKET_QUEUE_WORKER pWorker, PVBOXNETFLTPACKET_INFO pInfo)
{
}
/**
* puts the packet to the queue
*
* @return NDIST_STATUS_SUCCESS iff the packet was enqueued successfully
* and error status otherwise.
* NOTE: that the success status does NOT mean that the packet processing is completed, but only that it was enqueued successfully
* the packet can be returned to the caller protocol/moniport only in case the bReleasePacket was set to true (in this case the copy of the packet was enqueued)
* or if vboxNetFltWinQuEnqueuePacket failed, i.e. the packet was NOT enqueued
*/
DECLHIDDEN(NDIS_STATUS) vboxNetFltWinQuEnqueuePacket(PVBOXNETFLTINS pInstance, PVOID pPacket, const UINT fPacketFlags)
{
do
{
if (fPacketFlags & PACKET_COPY)
{
UINT uBytesCopied = 0;
/* the packet is Ndis packet */
NULL,
&pBuffer,
if (fStatus != NDIS_STATUS_SUCCESS)
{
AssertFailed();
break;
}
if (!pInfo)
{
AssertFailed();
/* TODO: what status to set? */
break;
}
/* the packet we are queueing is SG, add PACKET_SG to flags */
if (fStatus != NDIS_STATUS_SUCCESS)
{
AssertFailed();
break;
}
}
else
{
if (!pInfo)
{
AssertFailed();
/* TODO: what status to set? */
break;
}
}
} while (0);
return fStatus;
}
#endif
/*
* netflt
*/
#ifndef VBOXNETADP
{
int rc;
/* 1. serialize */
if (RT_SUCCESS(rc))
{
/* 2. set pNetFlt->u.s.pSynchRequest */
/* 3. call NdisRequest */
if (fRequestStatus == NDIS_STATUS_PENDING)
{
/* 3.1 if pending wait and assign the resulting status */
}
/* 4. clear the pNetFlt->u.s.pSynchRequest */
return fRequestStatus;
}
return NDIS_STATUS_FAILURE;
}
{
if (status != NDIS_STATUS_SUCCESS)
{
/* TODO */
AssertFailed();
}
return status;
}
DECLHIDDEN(NDIS_STATUS) vboxNetFltWinQueryPhysicalMedium(PVBOXNETFLTINS pNetFlt, NDIS_PHYSICAL_MEDIUM * pMedium)
{
if (Status != NDIS_STATUS_SUCCESS)
{
if (Status == NDIS_STATUS_NOT_SUPPORTED || Status == NDIS_STATUS_NOT_RECOGNIZED || Status == NDIS_STATUS_INVALID_OID)
{
}
else
{
AssertFailed();
}
}
return Status;
}
{
/** @todo r=bird: This is too slow and is probably returning the wrong
* information. What we're interested in is whether someone besides us
* has put the interface into promiscuous mode. */
if (status != NDIS_STATUS_SUCCESS)
{
/* TODO */
AssertFailed();
return false;
}
return (filter & NDIS_PACKET_TYPE_PROMISCUOUS) != 0;
}
{
/** @todo Need to report changes to the switch via:
* pThis->pSwitchPort->pfnReportPromiscuousMode(pThis->pSwitchPort, fPromisc);
*/
{
if (fStatus != NDIS_STATUS_SUCCESS)
{
/* TODO: */
AssertFailed();
return fStatus;
}
{
/* the cache was not initialized yet, initiate it with the current filter value */
}
if (bYes)
{
}
else
{
fOurFilter = 0;
}
if (fExpectedFilter != fFilter)
{
if (fStatus != NDIS_STATUS_SUCCESS)
{
/* TODO */
AssertFailed();
return fStatus;
}
}
return fStatus;
}
return NDIS_STATUS_NOT_SUPPORTED;
}
#else /* if defined VBOXNETADP */
/**
* Generates a new unique MAC address based on our vendor ID
*/
{
/* temporary use a time info */
}
{
/* validate parameters */
AssertReturn(pNdisString->MaximumLength >= 13*sizeof(pNdisString->Buffer[0]), VERR_INVALID_PARAMETER);
for (int i = 0; i < 6; i++)
{
pString += 2;
}
*pString = L'\0';
return VINF_SUCCESS;
}
{
if (c >= L'A' && c <= L'F')
{
}
else if (c >= L'a' && c <= L'f')
{
}
else if (c >= L'0' && c <= L'9')
{
*pv = (c - L'0');
}
else
{
return VERR_INVALID_PARAMETER;
}
return VINF_SUCCESS;
}
{
int i, rc;
/* validate parameters */
for (i = 0; i < 6; i++)
{
if (RT_FAILURE(rc))
{
break;
}
if (RT_FAILURE(rc))
{
break;
}
pString += 2;
}
return rc;
}
#endif
/**
* creates a NDIS_PACKET from the PINTNETSG
*/
DECLHIDDEN(PNDIS_PACKET) vboxNetFltWinNdisPacketFromSG(PVBOXNETFLTINS pNetFlt, PINTNETSG pSG, PVOID pBufToFree, bool bToWire, bool bCopyMemory)
{
/** @todo Hrmpf, how can we fix this assumption? I fear this'll cause data
* corruption and maybe even BSODs ... */
#ifdef VBOXNETADP
#else
NdisAllocatePacket(&fStatus, &pPacket, bToWire ? pNetFlt->u.s.WinIf.hSendPacketPool : pNetFlt->u.s.WinIf.hRecvPacketPool);
#endif
if (fStatus == NDIS_STATUS_SUCCESS)
{
/* @todo: generally we do not always need to zero-initialize the complete OOB data here, reinitialize only when/what we need,
* however we DO need to reset the status for the packets we indicate via NdisMIndicateReceivePacket to avoid packet loss
* in case the status contains NDIS_STATUS_RESOURCES */
if (bCopyMemory)
{
if (fStatus == NDIS_STATUS_SUCCESS)
}
else
{
}
if (fStatus == NDIS_STATUS_SUCCESS)
{
#ifdef VBOXNETADP
#else
#endif
if (fStatus == NDIS_STATUS_SUCCESS)
{
if (bToWire)
{
#ifdef VBOX_LOOPBACK_USEFLAGS
/* set "don't loopback" flags */
#else
NdisGetPacketFlags(pPacket) = 0;
#endif
}
else
{
/* we must set the header size on receive */
/* NdisAllocatePacket zero-initializes the OOB data,
* but keeps the packet flags, clean them here */
NdisGetPacketFlags(pPacket) = 0;
}
/* TODO: set out of bound data */
}
else
{
AssertFailed();
if (bCopyMemory)
{
}
}
}
else
{
AssertFailed();
}
}
else
{
}
return pPacket;
}
/*
* frees NDIS_PACKET created with vboxNetFltWinNdisPacketFromSG
*/
{
do
{
{
if (bFreeMem)
{
}
}
else
{
break;
}
} while (true);
}
#if !defined(VBOXNETADP)
{
}
#endif
/*
* NetFlt driver unload function
*/
{
int rc;
if (RT_FAILURE(rc))
{
/* TODO: we can not prevent driver unload here */
AssertFailed();
}
#ifndef VBOXNETADP
#endif
/* don't use logging or any RT after de-init */
}
{
int rc;
/* the idc registration is initiated via IOCTL since our driver
* can be loaded when the VBoxDrv is not in case we are a Ndis IM driver */
if (RT_SUCCESS(rc))
{
if (Status == STATUS_SUCCESS)
{
/* note: we do it after we initialize the Job Queue */
NULL, /* PULONG BuildNumber OPTIONAL */
NULL /* PUNICODE_STRING CSDVersion OPTIONAL */
);
{
/* this is Win2k, we don't support it actually, but just in case */
}
if (Status == NDIS_STATUS_SUCCESS)
{
#ifndef VBOXNETADP
if (Status == NDIS_STATUS_SUCCESS)
#endif
{
#ifndef VBOXNETADP
#endif
return STATUS_SUCCESS;
//#ifndef VBOXNETADP
// vboxNetFltWinPtDeregister(&g_VBoxNetFltGlobalsWin.Pt);
//#endif
}
}
}
}
else
{
}
return Status;
}
#ifndef VBOXNETADP
/**
* creates and initializes the packet to be sent to the underlying miniport given a packet posted to our miniport edge
* according to DDK docs we must create our own packet rather than posting the one passed to us
*/
DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPrepareSendPacket(PVBOXNETFLTINS pNetFlt, PNDIS_PACKET pPacket, PNDIS_PACKET *ppMyPacket)
{
if (Status == NDIS_STATUS_SUCCESS)
{
/* the rest will be filled on send */
#ifdef VBOX_LOOPBACK_USEFLAGS
#endif
}
else
{
*ppMyPacket = NULL;
}
return Status;
}
/**
* creates and initializes the packet to be sent to the upperlying protocol given a packet indicated to our protocol edge
* according to DDK docs we must create our own packet rather than posting the one passed to us
*/
DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPrepareRecvPacket(PVBOXNETFLTINS pNetFlt, PNDIS_PACKET pPacket, PNDIS_PACKET *ppMyPacket, bool bDpr)
{
if (bDpr)
{
}
else
{
}
if (Status == NDIS_STATUS_SUCCESS)
{
}
else
{
*ppMyPacket = NULL;
}
return Status;
}
#endif
/**
* initializes the VBOXNETFLTINS (our context structure) and binds to the given adapter
*/
#if defined(VBOXNETADP)
DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitBind(PVBOXNETFLTINS *ppNetFlt, NDIS_HANDLE hMiniportAdapter, PNDIS_STRING pBindToMiniportName /* actually this is our miniport name*/, NDIS_HANDLE hWrapperConfigurationContext)
#else
DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitBind(PVBOXNETFLTINS *ppNetFlt, PNDIS_STRING pOurMiniportName, PNDIS_STRING pBindToMiniportName)
#endif
{
do
{
int rc;
USHORT cbAnsiName = pBindToMiniportName->Length;/* the length is is bytes ; *2 ;RtlUnicodeStringToAnsiSize(pBindToMiniportName)*/
# ifndef VBOXNETADP
# else
# endif
AnsiString.Length = 0;
if (Status != STATUS_SUCCESS)
{
break;
}
if (RT_FAILURE(rc))
{
AssertFailed();
break;
}
if (rc == VINF_ALREADY_INITIALIZED)
{
/* the case when our adapter was unbound while IntNet was connected to it */
/* the instance remains valid until IntNet disconnects from it, we simply search and re-use it*/
if (RT_FAILURE(rc))
{
AssertFailed();
/* release netflt */
vboxNetFltRelease(pInstance, false);
break;
}
}
} while (FALSE);
return Status;
}
/*
* deinitializes the VBOXNETFLTWIN
*/
{
#ifndef VBOXNETADP
int rc;
#endif
#ifndef VBOXNETADP
{
}
# if defined(DEBUG_NETFLT_LOOPBACK) || !defined(VBOX_LOOPBACK_USEFLAGS)
# endif
#endif
/* NOTE: NULL is a valid handle */
}
#ifndef VBOXNETADP
DECLHIDDEN(NDIS_STATUS) vboxNetFltWinPtInitWinIf(PVBOXNETFLTWIN pWinIf, IN PNDIS_STRING pOurDeviceName)
#else
#endif
{
#ifndef VBOXNETADP
int rc;
#endif
if (Status == NDIS_STATUS_SUCCESS)
{
/* NOTE: NULL is a valid handle !!! */
if (Status == NDIS_STATUS_SUCCESS)
{
#ifndef VBOXNETADP
if (Status == NDIS_STATUS_SUCCESS)
{
# if defined(DEBUG_NETFLT_LOOPBACK) || !defined(VBOX_LOOPBACK_USEFLAGS)
# endif
sizeof (PVBOXNETFLT_PKTRSVD_PT));
if (Status == NDIS_STATUS_SUCCESS)
{
if (RT_SUCCESS(rc))
{
if (Status == NDIS_STATUS_SUCCESS)
{
#endif
return NDIS_STATUS_SUCCESS;
#ifndef VBOXNETADP
}
}
else
{
}
}
}
#endif
}
}
return Status;
}
/**
* match packets
*/
#define FIRST_LIST_ENTRY NEXT_LIST_ENTRY
#define LAST_LIST_ENTRY PREV_LIST_ENTRY
#ifndef VBOXNETADP
#ifdef DEBUG_misha
{
UINT i = 0;
return NULL;
return NULL;
return pEth;
}
{
return NULL;
return NULL;
}
{
if (!pHdr)
return false;
return false;
return false;
return true;
}
{
if (!pHdr)
return false;
return false;
return false;
return true;
}
#endif
# if !defined(VBOX_LOOPBACK_USEFLAGS) || defined(DEBUG_NETFLT_PACKETS)
/*
* answers whether the two given packets match based on the packet length and the first cbMatch bytes of the packets
* if cbMatch < 0 matches complete packets.
*/
DECLHIDDEN(bool) vboxNetFltWinMatchPackets(PNDIS_PACKET pPacket1, PNDIS_PACKET pPacket2, const INT cbMatch)
{
bool bMatch = true;
#ifdef DEBUG_NETFLT_PACKETS
bool bCompleteMatch = false;
#endif
{
bMatch = false;
}
else
{
UINT ucbLength2Match = 0;
{
/* NOTE: assuming uTotalPacketLength1 == uTotalPacketLength2*/
#ifdef DEBUG_NETFLT_PACKETS
bCompleteMatch = true;
#endif
}
else
{
}
for (;;)
{
if (!cbLength1)
{
}
else
{
}
if (!cbLength2)
{
}
else
{
}
{
bMatch = false;
break;
}
if (!ucbMatch)
break;
}
}
#ifdef DEBUG_NETFLT_PACKETS
if (bMatch && !bCompleteMatch)
{
/* check that the packets fully match */
}
#endif
return bMatch;
}
/*
* answers whether the ndis packet and PINTNETSG match based on the packet length and the first cbMatch bytes of the packet and PINTNETSG
* if cbMatch < 0 matches complete packets.
*/
DECLHIDDEN(bool) vboxNetFltWinMatchPacketAndSG(PNDIS_PACKET pPacket, PINTNETSG pSG, const INT cbMatch)
{
bool bMatch = true;
bool bCompleteMatch = false;
UINT i = 0;
{
AssertFailed();
bMatch = false;
}
else
{
UINT ucbLength2Match = 0;
{
/* NOTE: assuming uTotalPacketLength1 == uTotalPacketLength2*/
bCompleteMatch = true;
}
else
{
}
for (;;)
{
if (!cbLength1)
{
}
else
{
}
if (!cbLength2)
{
i++;
}
else
{
}
{
bMatch = false;
AssertFailed();
break;
}
if (!ucbMatch)
break;
}
}
if (bMatch && !bCompleteMatch)
{
/* check that the packets fully match */
}
return bMatch;
}
# if 0
/*
* answers whether the two PINTNETSGs match based on the packet length and the first cbMatch bytes of the PINTNETSG
* if cbMatch < 0 matches complete packets.
*/
{
bool bMatch = true;
bool bCompleteMatch = false;
{
AssertFailed();
bMatch = false;
}
else
{
{
/* NOTE: assuming uTotalPacketLength1 == uTotalPacketLength2*/
bCompleteMatch = true;
}
else
{
}
do
{
if (!cbLength1)
{
i1++;
}
if (!cbLength2)
{
i2++;
}
{
bMatch = false;
AssertFailed();
break;
}
} while (ucbMatch);
}
if (bMatch && !bCompleteMatch)
{
/* check that the packets fully match */
}
return bMatch;
}
# endif
# endif
#endif
static void vboxNetFltWinFiniNetFltBase()
{
do
{
/*
* Undo the work done during start (in reverse order).
*/
RTR0Term();
} while (0);
}
static int vboxNetFltWinTryFiniIdc()
{
int rc;
{
if (RT_SUCCESS(rc))
{
g_bVBoxIdcInitialized = false;
}
}
else
{
rc = VINF_SUCCESS;
}
return rc;
}
static int vboxNetFltWinFiniNetFlt()
{
int rc = vboxNetFltWinTryFiniIdc();
if (RT_SUCCESS(rc))
{
}
return rc;
}
/**
* base netflt initialization
*/
static int vboxNetFltWinInitNetFltBase()
{
int rc;
do
{
if (!RT_SUCCESS(rc))
{
break;
}
if (!RT_SUCCESS(rc))
{
RTR0Term();
break;
}
}while (0);
return rc;
}
/**
* initialize IDC
*/
static int vboxNetFltWinInitIdc()
{
int rc;
do
{
{
break;
}
/*
* connect to the support driver.
*
* This will call back vboxNetFltOsOpenSupDrv (and maybe vboxNetFltOsCloseSupDrv)
* for establishing the connect to the support driver.
*/
if (!RT_SUCCESS(rc))
{
break;
}
g_bVBoxIdcInitialized = true;
} while (0);
return rc;
}
{
int rc = vboxNetFltWinInitIdc();
if (RT_FAILURE(rc))
{
if (!bInterupted)
{
if (!bInterupted)
{
return;
}
}
/* it's interrupted */
}
}
static int vboxNetFltWinStopInitIdcProbing()
{
return VERR_INVALID_STATE;
return g_VBoxInitIdcInfo.rc;
}
static int vboxNetFltWinStartInitIdcProbing()
{
g_VBoxInitIdcInfo.bStop = false;
g_VBoxInitIdcInfo.bInitialized = true;
vboxNetFltWinJobInit(&g_VBoxInitIdcInfo.Job, vboxNetFltWinInitIdcProbingWorker, &g_VBoxInitIdcInfo, false);
return VINF_SUCCESS;
}
static int vboxNetFltWinInitNetFlt()
{
int rc;
do
{
if (RT_FAILURE(rc))
{
AssertFailed();
break;
}
/*
* connect to the support driver.
*
* This will call back vboxNetFltOsOpenSupDrv (and maybe vboxNetFltOsCloseSupDrv)
* for establishing the connect to the support driver.
*/
rc = vboxNetFltWinInitIdc();
if (RT_FAILURE(rc))
{
AssertFailed();
break;
}
} while (0);
return rc;
}
/* detach*/
{
#ifndef VBOXNETADP
#endif
#ifndef VBOXNETFLT_NO_PACKET_QUEUE
#endif
return VINF_SUCCESS;
}
{
#ifndef VBOXNETFLT_NO_PACKET_QUEUE
#endif
return NDIS_STATUS_SUCCESS;
}
/* detach*/
{
int rc;
/* paranoia to ensure the instance is not removed while we're waiting on the mutex
* in case ndis does something unpredictable, e.g. calls our miniport halt independently
* from protocol unbind and concurrently with it*/
vboxNetFltRetain(pNetFlt, false);
if (RT_SUCCESS(rc))
{
#ifndef VBOXNETADP
#endif
{
#ifndef VBOXNETADP
#else
#endif
#ifndef VBOXNETADP
#endif
/* we're unbinding, make an unbind-related release */
vboxNetFltRelease(pNetFlt, false);
}
else
{
#ifndef VBOXNETADP
#endif
if (!bOnUnbind)
{
}
}
}
else
{
}
/* release for the retain we made before waining on the mutex */
vboxNetFltRelease(pNetFlt, false);
return Status;
}
/**
* Checks if the host (not us) has put the adapter in promiscuous mode.
*
* @returns true if promiscuous, false if not.
* @param pThis The instance.
*/
{
#ifndef VBOXNETADP
{
bool bPromiscuous;
if (!vboxNetFltWinReferenceWinIf(pThis))
return false;
bPromiscuous = (pThis->u.s.WinIf.fUpperProtocolSetFilter & NDIS_PACKET_TYPE_PROMISCUOUS) == NDIS_PACKET_TYPE_PROMISCUOUS;
/*vboxNetFltWinIsPromiscuous(pAdapt);*/
return bPromiscuous;
}
return false;
#else
return true;
#endif
}
/**
* Report the MAC address, promiscuous mode setting, GSO capabilities and
* no-preempt destinations to the internal network.
*
* Does nothing if we're not currently connected to an internal network.
*
* @param pThis The instance data.
*/
{
/** @todo Keep these up to date, esp. the promiscuous mode bit. */
if (pThis->pSwitchPort
{
/** @todo We should be able to do pfnXmit at DISPATCH_LEVEL... */
}
}
/**
* Worker for vboxNetFltWinAttachToInterface.
*
* @param pAttachInfo Structure for communicating with
* vboxNetFltWinAttachToInterface.
*/
{
int rc;
/* to ensure we're not removed while we're here */
vboxNetFltRetain(pThis, false);
if (RT_SUCCESS(rc))
{
#ifndef VBOXNETADP
#endif
{
if (pAttachInfo->fRediscovery)
{
/* rediscovery means adaptor bind is performed while intnet is already using it
* i.e. adaptor was unbound while being used by intnet and now being bound back again */
Assert(((VBOXNETFTLINSSTATE)ASMAtomicUoReadU32((uint32_t volatile *)&pThis->enmState)) == kVBoxNetFltInsState_Connected);
}
#ifndef VBOXNETADP
#else
#endif
if (Status == NDIS_STATUS_SUCCESS)
{
#ifndef VBOXNETADP
Status = vboxNetFltWinPtDoBinding(pThis, pAttachInfo->pCreateContext->pOurName, pAttachInfo->pCreateContext->pBindToName);
#else
Status = vboxNetFltWinMpDoInitialization(pThis, pAttachInfo->pCreateContext->hMiniportAdapter, pAttachInfo->pCreateContext->hWrapperConfigurationContext);
#endif
if (Status == NDIS_STATUS_SUCCESS)
{
if (!pAttachInfo->fRediscovery)
{
}
#ifndef VBOXNETADP
#endif
{
#ifndef VBOXNETADP
#endif
/* 4. mark as connected */
vboxNetFltRelease(pThis, false);
/* 5. Report MAC address, promiscuousness and GSO capabilities. */
return;
}
if (!pAttachInfo->fRediscovery)
{
}
#ifndef VBOXNETADP
vboxNetFltWinPtDoUnbinding(pThis, true);
#else
#endif
}
}
#ifndef VBOXNETADP
#endif
}
}
else
{
}
vboxNetFltRelease(pThis, false);
return;
}
/**
* Common code for vboxNetFltOsInitInstance and
* vboxNetFltOsMaybeRediscovered.
*
* @returns IPRT status code.
* @param pThis The instance.
* @param fRediscovery True if vboxNetFltOsMaybeRediscovered is calling,
* false if it's vboxNetFltOsInitInstance.
*/
{
}
{
switch (pIrpSl->MajorFunction)
{
case IRP_MJ_DEVICE_CONTROL:
break;
case IRP_MJ_CREATE:
case IRP_MJ_CLEANUP:
case IRP_MJ_CLOSE:
break;
default:
Assert(0);
break;
}
return Status;
}
{
return Status;
}
{
if (Status == NDIS_STATUS_SUCCESS)
{
}
return Status;
}
{
NDIS_STATUS Status = KeWaitForSingleObject(&pGlobals->SynchEvent, Executive, KernelMode, FALSE, NULL);
if (Status == STATUS_SUCCESS)
{
{
if (Status == NDIS_STATUS_SUCCESS)
{
}
}
else
{
}
}
else
{
/* should never happen actually */
Assert(0);
}
return Status;
}
{
NDIS_STATUS Status = KeWaitForSingleObject(&pGlobals->SynchEvent, Executive, KernelMode, FALSE, NULL);
if (Status == STATUS_SUCCESS)
{
if (!(--pGlobals->cDeviceRefs))
{
}
else
{
}
}
else
{
/* should never happen actually */
Assert(0);
}
return Status;
}
/* reference the driver module to prevent driver unload */
DECLHIDDEN(void) vboxNetFltWinDrvReference()
{
}
/* dereference the driver module to prevent driver unload */
{
}
/*
*
* The OS specific interface definition
*
*/
{
/* AttachToInterface true if disconnected */
}
{
int rc = VINF_SUCCESS;
#ifndef VBOXNETADP
if (fDst & INTNETTRUNKDIR_WIRE)
{
cRefs++;
}
if (fDst & INTNETTRUNKDIR_HOST)
{
cRefs++;
}
#else
{
cRefs = 1;
}
#endif
{
return VERR_GENERAL_FAILURE;
}
#ifndef VBOXNETADP
if (fDst & INTNETTRUNKDIR_WIRE)
{
true /*fToWire*/, true /*fCopyMemory*/);
if (pPacket)
{
#ifndef VBOX_LOOPBACK_USEFLAGS
/* force "don't loopback" flags to prevent loopback branch invocation in any case
* to avoid ndis misbehave */
#else
/* this is done by default in vboxNetFltWinNdisPacketFromSG */
#endif
#if defined(DEBUG_NETFLT_PACKETS) || !defined(VBOX_LOOPBACK_USEFLAGS)
#endif
if (fStatus != NDIS_STATUS_PENDING)
{
#if defined(DEBUG_NETFLT_PACKETS) || !defined(VBOX_LOOPBACK_USEFLAGS)
/* the status is NOT pending, complete the packet */
#endif
if (!NT_SUCCESS(fStatus))
{
/* TODO: convert status to VERR_xxx */
}
vboxNetFltWinFreeSGNdisPacket(pPacket, true);
}
else
{
/* pending, dereference on packet complete */
cRefs--;
}
}
else
{
AssertFailed();
rc = VERR_NO_MEMORY;
}
}
#endif
#ifndef VBOXNETADP
if (fDst & INTNETTRUNKDIR_HOST)
#else
if (cRefs)
#endif
{
false /*fToWire*/, true /*fCopyMemory*/);
if (pPacket)
{
cRefs--;
#ifdef VBOXNETADP
#endif
}
else
{
AssertFailed();
#ifdef VBOXNETADP
#endif
rc = VERR_NO_MEMORY;
}
}
if (cRefs)
{
}
return rc;
}
{
#ifndef VBOXNETADP
#endif
/* we first wait for all pending ops to complete
* this might include all packets queued for processing */
for (;;)
{
if (fActive)
{
if (!pThis->u.s.cModePassThruRefs)
{
break;
}
}
else
{
if (!pThis->u.s.cModeNetFltRefs)
{
break;
}
}
}
if (!vboxNetFltWinReferenceWinIf(pThis))
return;
#ifndef VBOXNETADP
if (fActive)
{
#ifdef DEBUG_misha
bool bPromiscSupported;
if (Status != NDIS_STATUS_SUCCESS)
{
LogRel(("vboxNetFltWinQueryPhysicalMedium failed, Status (0x%x), setting medium to NdisPhysicalMediumUnspecified\n", Status));
if (Status != NDIS_STATUS_NOT_SUPPORTED)
{
LogRel(("vboxNetFltWinQueryPhysicalMedium failed, Status (0x%x), setting medium to NdisPhysicalMediumUnspecified\n", Status));
}
}
else
{
LogRel(("(SUCCESS) vboxNetFltWinQueryPhysicalMedium SUCCESS\n"));
}
/*|| PhMedium == NdisPhysicalMediumWiMax */
));
#endif
}
{
if (Status != NDIS_STATUS_SUCCESS)
{
AssertFailed();
}
}
#else
# ifdef VBOXNETADP_REPORT_DISCONNECTED
if (fActive)
{
0);
}
else
{
0);
}
#else
if (fActive)
{
/* indicate status change to make the ip settings be re-picked for dhcp */
0);
0);
}
# endif
#endif
return;
}
{
}
{
#if !defined(VBOXNETADP) || !defined(VBOXNETFLT_NO_PACKET_QUEUE)
#endif
/* this is not a rediscovery, initialize Mac cache */
{
#ifndef VBOXNETADP
if (Status == NDIS_STATUS_SUCCESS)
#endif
{
#ifdef VBOXNETFLT_NO_PACKET_QUEUE
#else
if (Status == NDIS_STATUS_SUCCESS)
{
}
else
{
}
#endif
}
#ifndef VBOXNETADP
else
{
}
#endif
}
else
{
}
}
{
}
{
return vboxNetFltWinConnectIt(pThis);
}
{
}
{
if (RT_SUCCESS(rc))
{
if (RT_SUCCESS(rc))
{
return rc;
}
}
return rc;
}
{
pThis->u.s.cModeNetFltRefs = 0;
pThis->u.s.cModePassThruRefs = 0;
#ifndef VBOXNETADP
#endif
return VINF_SUCCESS;
}
{
}
{
/* Nothing to do */
return VINF_SUCCESS;
}
{
/* Nothing to do */
return VINF_SUCCESS;
}