Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

4839 lines
130 KiB

/*
************************************************************************
Copyright (c) 1996-1997 Microsoft Corporation
Module Name:
gpcmain.c
Abstract:
This file contains initialization stuff for the GPC
and all the exposed APIs
Author:
Ofer Bar - April 15, 1997
Environment:
Kernel mode
Revision History:
************************************************************************
*/
#include "gpcpre.h"
/*
/////////////////////////////////////////////////////////////////
//
// globals
//
/////////////////////////////////////////////////////////////////
*/
NDIS_STRING DriverName = NDIS_STRING_CONST( "\\Device\\Gpc" );
GLOBAL_BLOCK glData;
GPC_STAT glStat;
static _init_driver = FALSE;
ULONG GpcMinorVersion = 0;
#ifdef STANDALONE_DRIVER
GPC_EXPORTED_CALLS glGpcExportedCalls;
#endif
#if DBG
CHAR VersionTimestamp[] = __DATE__ " " __TIME__;
#endif
// tags
ULONG QueuedNotificationTag = 'nqpQ';
ULONG PendingIrpTag = 'ippQ';
ULONG CfInfoTag = 'icpQ';
ULONG ClientTag = 'tcpQ';
ULONG PatternTag = 'appQ';
ULONG HandleFactoryTag = 'fhpQ'; // Gphf
ULONG PathHashTag = 'hppQ';
ULONG RhizomeTag = 'zrpQ';
ULONG GenPatternDbTag = 'dppQ';
ULONG FragmentDbTag = 'dfpQ';
ULONG ClassificationFamilyTag = 'fcpQ';
ULONG CfInfoDataTag = 'dcpQ';
ULONG ClassificationBlockTag = 'bcpQ';
ULONG ProtocolTag = 'tppQ';
ULONG DebugTag = 'gdpQ';
ULONG RequestBlockTag = 'brpQ';
ULONG TcpPatternTag = 'ptpQ';
ULONG TcpQueryContextTag= 'qtpQ';
// Lookaside lists
NPAGED_LOOKASIDE_LIST ClassificationFamilyLL;
NPAGED_LOOKASIDE_LIST ClientLL;
NPAGED_LOOKASIDE_LIST PatternLL;
//NPAGED_LOOKASIDE_LIST CfInfoLL;
NPAGED_LOOKASIDE_LIST QueuedNotificationLL;
NPAGED_LOOKASIDE_LIST PendingIrpLL;
ULONG ClassificationFamilyLLSize = sizeof( CF_BLOCK );
ULONG ClientLLSize = sizeof( CLIENT_BLOCK );
ULONG PatternLLSize = sizeof( PATTERN_BLOCK );
ULONG CfInfoLLSize = sizeof( BLOB_BLOCK );
ULONG QueuedNotificationLLSize = sizeof( QUEUED_NOTIFY );
ULONG PendingIrpLLSize = sizeof( PENDING_IRP );
/*
/////////////////////////////////////////////////////////////////
//
// pragma
//
/////////////////////////////////////////////////////////////////
*/
//#pragma NDIS_INIT_FUNCTION(DriverEntry)
#if 0
#pragma NDIS_PAGEABLE_FUNCTION(DriverEntry)
#pragma NDIS_PAGEABLE_FUNCTION(GpcRegisterClient)
#pragma NDIS_PAGEABLE_FUNCTION(GpcDeregisterClient)
#pragma NDIS_PAGEABLE_FUNCTION(GpcAddCfInfo)
#pragma NDIS_PAGEABLE_FUNCTION(GpcAddPattern)
#pragma NDIS_PAGEABLE_FUNCTION(GpcAddCfInfoNotifyComplete)
#pragma NDIS_PAGEABLE_FUNCTION(GpcModifyCfInfo)
#pragma NDIS_PAGEABLE_FUNCTION(GpcModifyCfInfoNotifyComplete)
#pragma NDIS_PAGEABLE_FUNCTION(GpcRemoveCfInfo)
#pragma NDIS_PAGEABLE_FUNCTION(GpcRemoveCfInfoNotifyComplete)
#pragma NDIS_PAGEABLE_FUNCTION(GpcRemovePattern)
#endif
/*
/////////////////////////////////////////////////////////////////
//
// prototypes
//
/////////////////////////////////////////////////////////////////
*/
#if DBG
NTSTATUS
InitializeLog();
VOID
FreeDebugLog(
VOID);
#endif
VOID
GpcUnload (
IN PDRIVER_OBJECT DriverObject
);
/*
************************************************************************
InitGpc -
The initialization routine. It is getting called during load time
and is responsible to call other initialization code.
Arguments
none
Returns
GPC_STATUS
************************************************************************
*/
GPC_STATUS
InitGpc(void)
{
GPC_STATUS Status = STATUS_SUCCESS;
ULONG i, k;
TRACE(INIT, 0, 0, "InitGpc");
//
// init the global data
//
RtlZeroMemory(&glData, sizeof(glData));
InitializeListHead(&glData.CfList);
NDIS_INIT_LOCK(&glData.Lock);
//
// Create a new Request list for blocked requests... [276945]
//
InitializeListHead(&glData.gRequestList);
NDIS_INIT_LOCK(&glData.RequestListLock);
k = sizeof(PROTOCOL_BLOCK) * GPC_PROTOCOL_TEMPLATE_MAX;
GpcAllocMem(&glData.pProtocols, k, ProtocolTag);
if (glData.pProtocols == NULL) {
Status = GPC_STATUS_NO_MEMORY;
TRACE(INIT, Status, 0, "InitGpc==>");
return Status;
}
RtlZeroMemory(glData.pProtocols, k);
RtlZeroMemory(&glStat, sizeof(glStat));
for (i = 0; i < GPC_PROTOCOL_TEMPLATE_MAX; i++) {
if ((Status = InitPatternTimer(i)) != STATUS_SUCCESS) {
TRACE(INIT, Status, i, "InitGpc, timer==>");
break;
}
//
// init rest of strcture
//
glData.pProtocols[i].ProtocolTemplate = i;
glData.pProtocols[i].SpecificPatternCount = 0;
glData.pProtocols[i].AutoSpecificPatternCount = 0;
glData.pProtocols[i].GenericPatternCount = 0;
switch (i) {
case GPC_PROTOCOL_TEMPLATE_IP:
k = sizeof(GPC_IP_PATTERN);
break;
case GPC_PROTOCOL_TEMPLATE_IPX:
k = sizeof(GPC_IPX_PATTERN);
break;
default:
ASSERT(0);
}
glData.pProtocols[i].PatternSize = k;
//
// init specific pattern db
//
Status = InitSpecificPatternDb(&glData.pProtocols[i].SpecificDb, k);
if (!NT_SUCCESS(Status)) {
TRACE(INIT, Status, 0, "InitGpc==>");
break;
}
//
// init fragments db
//
Status = InitFragmentDb((PFRAGMENT_DB *)&glData.pProtocols[i].pProtocolDb);
if (!NT_SUCCESS(Status)) {
// SS202
//
UninitSpecificPatternDb(&glData.pProtocols[i].SpecificDb);
TRACE(INIT, Status, 0, "InitGpc==>");
break;
}
} // for (i...)
if (!NT_SUCCESS (Status)) {
TRACE(INIT, Status, 0, "InitGpc b");
goto Cleanup;
}
//
// init handle mapping table
//
Status = InitMapHandles();
if (!NT_SUCCESS(Status)) {
TRACE(INIT, Status, 0, "InitGpc b");
goto Cleanup;
}
//
// init classification index table
//
Status = InitClassificationHandleTbl(&glData.pCHTable);
if (!NT_SUCCESS(Status)) {
TRACE(INIT, Status, 0, "InitGpc c");
goto Cleanup;
}
#ifdef STANDALONE_DRIVER
//
// initialize the exported calls table
//
glGpcExportedCalls.GpcVersion = GpcMajorVersion;
glGpcExportedCalls.GpcGetCfInfoClientContextHandler = GpcGetCfInfoClientContext;
glGpcExportedCalls.GpcGetCfInfoClientContextWithRefHandler = GpcGetCfInfoClientContextWithRef;
glGpcExportedCalls.GpcGetUlongFromCfInfoHandler = GpcGetUlongFromCfInfo;
glGpcExportedCalls.GpcRegisterClientHandler = GpcRegisterClient;
glGpcExportedCalls.GpcDeregisterClientHandler = GpcDeregisterClient;
glGpcExportedCalls.GpcAddCfInfoHandler = GpcAddCfInfo;
glGpcExportedCalls.GpcAddPatternHandler = GpcAddPattern;
glGpcExportedCalls.GpcAddCfInfoNotifyCompleteHandler = GpcAddCfInfoNotifyComplete;
glGpcExportedCalls.GpcModifyCfInfoHandler = GpcModifyCfInfo;
glGpcExportedCalls.GpcModifyCfInfoNotifyCompleteHandler = GpcModifyCfInfoNotifyComplete;
glGpcExportedCalls.GpcRemoveCfInfoHandler = GpcRemoveCfInfo;
glGpcExportedCalls.GpcRemoveCfInfoNotifyCompleteHandler = GpcRemoveCfInfoNotifyComplete;
glGpcExportedCalls.GpcRemovePatternHandler = GpcRemovePattern;
glGpcExportedCalls.GpcClassifyPatternHandler = GpcClassifyPattern;
glGpcExportedCalls.GpcClassifyPacketHandler = GpcClassifyPacket;
//glGpcExportedCalls.GpcEnumCfInfoHandler = GpcEnumCfInfo;
#endif
#if DBG
//
// for the debug version, add a ULONG_PTR for the GPC mark ULONG.
// ULONG_PTR is used to ensure 8-byte alignment of the returned block on
// 64-bit platforms.
//
ClassificationFamilyLLSize += sizeof( ULONG_PTR );
ClientLLSize += sizeof( ULONG_PTR );
PatternLLSize += sizeof( ULONG_PTR );
CfInfoLLSize += sizeof( ULONG_PTR );
QueuedNotificationLLSize += sizeof( ULONG_PTR );
PendingIrpLLSize += sizeof( ULONG_PTR );
#endif
NdisInitializeNPagedLookasideList(&ClassificationFamilyLL,
NULL,
NULL,
0,
ClassificationFamilyLLSize,
ClassificationFamilyTag,
(USHORT)0);
NdisInitializeNPagedLookasideList(&ClientLL,
NULL,
NULL,
0,
ClientLLSize,
ClientTag,
(USHORT)0);
NdisInitializeNPagedLookasideList(&PatternLL,
NULL,
NULL,
0,
PatternLLSize,
PatternTag,
(USHORT)0);
/*NdisInitializeNPagedLookasideList(&CfInfoLL,
NULL,
NULL,
0,
CfInfoLLSize,
CfInfoTag,
(USHORT)0);*/
NdisInitializeNPagedLookasideList(&QueuedNotificationLL,
NULL,
NULL,
0,
QueuedNotificationLLSize,
QueuedNotificationTag,
(USHORT)0);
NdisInitializeNPagedLookasideList(&PendingIrpLL,
NULL,
NULL,
0,
PendingIrpLLSize,
PendingIrpTag,
(USHORT)0);
//
// Load cofiguration from registry
// loads default values if reg keys not available
//
GpcReadRegistry();
TRACE(INIT, Status, 0, "InitGpc==>");
Cleanup:
// SS202
// Much leaking above, needed common cleanup block
//
if (!NT_SUCCESS(Status))
{
UninitMapHandles();
if (glData.pProtocols != NULL)
{
for (i = 0; i < GPC_PROTOCOL_TEMPLATE_MAX; i++)
{
UninitSpecificPatternDb (&glData.pProtocols[i].SpecificDb);
UninitFragmentDb((PFRAGMENT_DB)glData.pProtocols[i].pProtocolDb);
}
GpcFreeMem(glData.pProtocols, ProtocolTag);
glData.pProtocols = NULL;
}
}
return Status;
}
/*
************************************************************************
DriverEntry -
The driver's entry point.
Arguments
DriverObject - Pointer to the driver object created by the system.
RegistryPath - string path to the registry.
Returns
NT_STATUS
************************************************************************
*/
NTSTATUS
DriverEntry(
IN PDRIVER_OBJECT DriverObject,
IN PUNICODE_STRING RegistryPath
)
{
GPC_STATUS Status;
ULONG dummy = 0;
PWCHAR EventLogString = DriverName.Buffer;
_init_driver = TRUE;
#if DBG
//
// first thing, init the trace log
//
Status = InitializeLog();
if (Status != STATUS_SUCCESS) {
KdPrint(("!!! GPC Failed to initialize trace log !!!\n", Status));
}
#endif
DriverObject->DriverUnload = GpcUnload;
//
// Call the init routine
//
Status = InitGpc();
if (NT_SUCCESS(Status)) {
//
// initialize the file system device
//
Status = (GPC_STATUS)IoctlInitialize(DriverObject, &dummy);
if (!NT_SUCCESS(Status)) {
NdisWriteEventLogEntry(DriverObject,
EVENT_TRANSPORT_REGISTER_FAILED,
GPC_ERROR_INIT_IOCTL,
1,
&EventLogString,
0,
NULL);
}
} else {
NdisWriteEventLogEntry(DriverObject,
EVENT_TRANSPORT_REGISTER_FAILED,
GPC_ERROR_INIT_MAIN,
1,
&EventLogString,
0,
NULL);
#if DBG
FreeDebugLog ();
#endif
}
#if DBG
if (!NT_SUCCESS(Status)) {
KdPrint(("!!! GPC loading Failed (%08X) !!!\n", Status));
}
#endif
return (NTSTATUS)Status;
} // end DriverEntry
VOID
GpcUnload(
IN PDRIVER_OBJECT DriverObject
)
{
ULONG i;
NdisDeleteNPagedLookasideList(&ClassificationFamilyLL);
NdisDeleteNPagedLookasideList(&ClientLL);
NdisDeleteNPagedLookasideList(&PatternLL);
// NdisDeleteNPagedLookasideList(&CfInfoLL);
NdisDeleteNPagedLookasideList(&QueuedNotificationLL);
NdisDeleteNPagedLookasideList(&PendingIrpLL);
UninitClassificationHandleTbl(glData.pCHTable);
UninitMapHandles();
for (i = 0; i < GPC_PROTOCOL_TEMPLATE_MAX; i++) {
UninitSpecificPatternDb (&glData.pProtocols[i].SpecificDb);
UninitFragmentDb((PFRAGMENT_DB)glData.pProtocols[i].pProtocolDb);
}
GpcFreeMem(glData.pProtocols, ProtocolTag);
#if DBG
FreeDebugLog ();
#endif
}
/*
************************************************************************
GpcGetCfInfoClientContext -
Returns the client context for blob
Arguments
ClientHandle - the calling client's handle
ClassificationHandle - needless to say
Returns
A CfInfo client context or NULL if the classification
handle is invalid
************************************************************************
*/
GPC_STATUS
GpcGetCfInfoClientContext(
IN GPC_HANDLE ClientHandle,
IN CLASSIFICATION_HANDLE ClassificationHandle,
OUT PGPC_CLIENT_HANDLE pClientCfInfoContext
)
{
PBLOB_BLOCK pBlob;
GPC_CLIENT_HANDLE h;
KIRQL CHirql;
NTSTATUS Status;
PCLASSIFICATION_BLOCK pCB;
TRACE(CLASSIFY, ClientHandle, ClassificationHandle, "GpcGetCfInfoClientContext");
pCB = NULL;
if (ClientHandle == NULL) {
*pClientCfInfoContext = NULL;
return GPC_STATUS_INVALID_PARAMETER;
}
READ_LOCK(&glData.ChLock, &CHirql);
pBlob = (PBLOB_BLOCK)dereference_HF_handle_with_cb(
glData.pCHTable,
ClassificationHandle,
GetCFIndexFromClient(ClientHandle));
if (pBlob == NULL) {
pCB = dereference_HF_handle(
glData.pCHTable,
ClassificationHandle);
READ_UNLOCK(&glData.ChLock, CHirql);
if (!pCB) {
Status = GPC_STATUS_INVALID_HANDLE;
} else {
Status = GPC_STATUS_NOT_FOUND;
}
*pClientCfInfoContext = 0;
return Status;
}
#if DBG
{
//
// Get the client index to reference into the ClientCtx table
//
ULONG t = GetClientIndexFromClient(ClientHandle);
ASSERT(t < MAX_CLIENTS_CTX_PER_BLOB);
TRACE(CLASSIFY, ClassificationHandle, pBlob->arClientCtx[t],
"GpcGetCfInfoClientContext (ctx)");
}
#endif
h = pBlob->arClientCtx[GetClientIndexFromClient(ClientHandle)];
READ_UNLOCK(&glData.ChLock, CHirql);
TRACE(CLASSIFY, pBlob, h, "GpcGetCfInfoClientContext==>");
*pClientCfInfoContext = h;
return GPC_STATUS_SUCCESS;
}
/*
************************************************************************
GpcGetCfInfoClientContextWithRef -
Returns the client context for blob and increments a Dword provided by
the client. This function can be used by clients to synchronize access
to their structures on the remove and send path.
Arguments
ClientHandle - the calling client's handle
ClassificationHandle - needless to say
Offset - Offset to location that needs to be incremented.
Returns
A CfInfo client context or NULL if the classification
handle is invalid
************************************************************************
*/
GPC_CLIENT_HANDLE
GpcGetCfInfoClientContextWithRef(
IN GPC_HANDLE ClientHandle,
IN CLASSIFICATION_HANDLE ClassificationHandle,
IN ULONG Offset
)
{
PBLOB_BLOCK pBlob;
GPC_CLIENT_HANDLE h;
KIRQL CHirql;
PULONG RefPtr = NULL;
TRACE(CLASSIFY, ClientHandle, ClassificationHandle, "GpcGetCfInfoClientContextWithRef");
if (ClientHandle == NULL)
return NULL;
READ_LOCK(&glData.ChLock, &CHirql);
pBlob = (PBLOB_BLOCK)dereference_HF_handle_with_cb(
glData.pCHTable,
ClassificationHandle,
GetCFIndexFromClient(ClientHandle));
if (pBlob == NULL) {
READ_UNLOCK(&glData.ChLock, CHirql);
return NULL;
}
#if DBG
{
//
// Get the client index to reference into the ClientCtx table
//
ULONG t = GetClientIndexFromClient(ClientHandle);
ASSERT(t < MAX_CLIENTS_CTX_PER_BLOB);
TRACE(CLASSIFY, ClassificationHandle, pBlob->arClientCtx[t],
"GpcGetCfInfoClientContextWithRef (ctx)");
}
#endif
h = pBlob->arClientCtx[GetClientIndexFromClient(ClientHandle)];
//
// As part of 390882, it has been noted that sometimes the handle can
// NULL, this could be either due to an Auto pattern or a generic
// pattern.
//
if (!h) {
READ_UNLOCK(&glData.ChLock, CHirql);
TRACE(CLASSIFY, pBlob, h, "GpcGetCfInfoClientContextWithRef==>");
return NULL;
}
// The GPC Clients wants GPC to increment the memory at this offset.
ASSERT(h);
RefPtr = (PULONG) (((PUCHAR)h) + Offset);
InterlockedIncrement(RefPtr);
//(*((PUCHAR)h + Offset))++;
READ_UNLOCK(&glData.ChLock, CHirql);
TRACE(CLASSIFY, pBlob, h, "GpcGetCfInfoClientContextWithRef==>");
return h;
}
/*
************************************************************************
GpcGetUlongFromCfInfo -
Returns a ulong in the blob data pointer from the classification handle for
the particular client.
Arguments
ClientHandle - the client handle
ClassificationHandle - the classification handle
Offset - oofset in bytes into the CfInfo structure
pValue - store for the returned value
Returns
GPC_STATUS
************************************************************************
*/
GPC_STATUS
GpcGetUlongFromCfInfo(
IN GPC_HANDLE ClientHandle,
IN CLASSIFICATION_HANDLE ClassificationHandle,
IN ULONG Offset,
IN PULONG pValue
)
{
KIRQL irql;
PCLASSIFICATION_BLOCK pCB;
PBLOB_BLOCK pBlob;
ASSERT( pValue );
TRACE(CLASSIFY, ClientHandle, ClassificationHandle, "GpcGetUlongFromCfInfo");
if (ClientHandle == NULL)
return GPC_STATUS_INVALID_PARAMETER;
READ_LOCK(&glData.ChLock, &irql);
pCB = (PCLASSIFICATION_BLOCK)dereference_HF_handle(
glData.pCHTable,
ClassificationHandle);
if (pCB == NULL) {
READ_UNLOCK(&glData.ChLock, irql);
return GPC_STATUS_INVALID_HANDLE;
}
pBlob = pCB->arpBlobBlock[GetCFIndexFromClient(ClientHandle)];
if (pBlob == NULL) {
TRACE(CLASSIFY, pBlob, 0, "GpcGetUlongFromCfInfo-->");
READ_UNLOCK(&glData.ChLock, irql);
return GPC_STATUS_NOT_FOUND;
}
TRACE(CLASSIFY, ClassificationHandle, pBlob->pClientData, "GpcGetUlongFromCfInfo (2)");
ASSERT( Offset+sizeof(ULONG) <= pBlob->ClientDataSize );
ASSERT( pBlob->pClientData );
if (pBlob->pClientData == NULL) {
READ_UNLOCK(&glData.ChLock, irql);
return (GPC_STATUS_FAILURE);
}
*pValue = *(PULONG)((PUCHAR)pBlob->pClientData + Offset);
READ_UNLOCK(&glData.ChLock, irql);
TRACE(CLASSIFY, pBlob, *pValue, "GpcGetUlongFromCfInfo==>");
return GPC_STATUS_SUCCESS;
}
/*
************************************************************************
GetClientCtxAndUlongFromCfInfo -
Returns a ulong in the blob data pointer AND the client context
from the classification handle for the particular client.
Arguments
ClientHandle - the client handle
ClassificationHandle - the classification handle
Offset - oofset in bytes into the CfInfo structure
pValue - store for the returned value
Returns
GPC_STATUS
************************************************************************
*/
GPC_STATUS
GetClientCtxAndUlongFromCfInfo(
IN GPC_HANDLE ClientHandle,
IN OUT PCLASSIFICATION_HANDLE pClassificationHandle,
OUT PGPC_CLIENT_HANDLE pClientCfInfoContext,
IN ULONG Offset,
IN PULONG pValue
)
{
PCLASSIFICATION_BLOCK pCB;
KIRQL irql;
PBLOB_BLOCK pBlob;
ASSERT( ClientHandle );
ASSERT( pClientCfInfoContext || pValue );
TRACE(CLASSIFY, ClientHandle, pClassificationHandle, "GetClientCtxAndUlongFromCfInfo");
READ_LOCK(&glData.ChLock, &irql);
pCB = (PCLASSIFICATION_BLOCK)dereference_HF_handle(
glData.pCHTable,
*pClassificationHandle
);
TRACE(CLASSIFY, pCB, GetCFIndexFromClient(ClientHandle), "GetClientCtxAndUlongFromCfInfo (2)");
if (pCB == NULL) {
//
// didn't find the reference, which means the CH is probably invalid
// reset it to 0 to indicate the caller that it should add a new one
//
*pClassificationHandle = 0;
READ_UNLOCK(&glData.ChLock, irql);
return GPC_STATUS_NOT_FOUND;
}
ASSERT(GetClientIndexFromClient(ClientHandle) < MAX_CLIENTS_CTX_PER_BLOB);
pBlob = pCB->arpBlobBlock[GetCFIndexFromClient(ClientHandle)];
if (pBlob == NULL) {
TRACE(CLASSIFY, pBlob, 0, "GetClientCtxAndUlongFromCfInfo-->");
READ_UNLOCK(&glData.ChLock, irql);
return GPC_STATUS_NOT_FOUND;
}
TRACE(CLASSIFY, *pClassificationHandle, pBlob->pClientData, "GetClientCtxAndUlongFromCfInfo (3)");
ASSERT( Offset+sizeof(ULONG) <= pBlob->ClientDataSize );
ASSERT( pBlob->pClientData );
if (pClientCfInfoContext) {
*pClientCfInfoContext = pBlob->arClientCtx[GetClientIndexFromClient(ClientHandle)];
TRACE(CLASSIFY, pBlob, *pClientCfInfoContext, "GetClientCtxAndUlongFromCfInfo==>");
}
if (pValue) {
*pValue = *(PULONG)((PUCHAR)pBlob->pClientData + Offset);
TRACE(CLASSIFY, pBlob, *pValue, "GetClientCtxAndUlongFromCfInfo==>");
}
READ_UNLOCK(&glData.ChLock, irql);
return GPC_STATUS_SUCCESS;
}
/*
************************************************************************
GpcRegisterClient -
This will register the client in the GPC and return a client handle.
If another client already registered for the same CF, we link this one
on a list for the CF. The first client for the CF will cause a CF block
to be created. CFs are identified by CfName. The other parameters will also
be set in the client's block.
Arguments
CfId - Id of the classification family
Flags - operation modes for the client:
CF_FRAGMENT
MaxPriorities - max number of priorities the client will ever use
pClientFuncList - list of callback functions
ClientContext - client context, GPC will use it in callbacks
pClientHandle - OUT, the returned client handle
Returns
GPC_STATUS
************************************************************************
*/
GPC_STATUS
GpcRegisterClient(
IN ULONG CfId,
IN ULONG Flags,
IN ULONG MaxPriorities,
IN PGPC_CLIENT_FUNC_LIST pClientFuncList,
IN GPC_CLIENT_HANDLE ClientContext,
OUT PGPC_HANDLE pClientHandle
)
{
GPC_STATUS Status = GPC_STATUS_SUCCESS;
PCF_BLOCK pCf;
PCLIENT_BLOCK pClient= NULL;
ULONG i;
PLIST_ENTRY pHead, pEntry;
KIRQL irql;
TRACE(REGISTER, CfId, ClientContext, "GpcRegisterClient");
*pClientHandle = NULL;
if (!_init_driver) {
return GPC_STATUS_NOTREADY;
}
//
// verify the CF Id
//
if (CfId >= GPC_CF_MAX) {
TRACE(REGISTER, GPC_STATUS_INVALID_PARAMETER, CfId, "GpcRegisterClient-->");
StatInc(RejectedCf);
return GPC_STATUS_INVALID_PARAMETER;
}
//
// verify the maximum number of priorities
//
if (MaxPriorities > GPC_PRIORITY_MAX) {
TRACE(REGISTER, GPC_STATUS_INVALID_PARAMETER, MaxPriorities, "GpcRegisterClient~~>");
StatInc(RejectedCf);
return GPC_STATUS_INVALID_PARAMETER;
}
if (MaxPriorities == 0) {
MaxPriorities = 1;
}
//
// find the CF or create a new one
//
NDIS_LOCK(&glData.Lock);
pHead = &glData.CfList;
pEntry = pHead->Flink;
pCf = NULL;
while (pCf == NULL && pEntry != pHead) {
pCf = CONTAINING_RECORD(pEntry, CF_BLOCK, Linkage);
if (pCf->AssignedIndex != CfId) {
pCf = NULL;
}
pEntry = pEntry->Flink;
}
if (pCf == NULL) {
//
// create a new CF
//
pCf = CreateNewCfBlock(CfId, MaxPriorities);
if (pCf == NULL) {
NDIS_UNLOCK(&glData.Lock);
return GPC_STATUS_NO_MEMORY;
}
//
// add the new CF to the list
//
GpcInsertTailList(&glData.CfList, &pCf->Linkage);
}
//
// grab the CF lock before releasing the global lock
//
NDIS_UNLOCK(&glData.Lock);
RSC_WRITE_LOCK(&pCf->ClientSync, &irql);
NDIS_LOCK(&pCf->Lock);
//
// create a new client block and chain it on the CF block
//
pClient = CreateNewClientBlock();
if (pClient == NULL) {
//
// oops
//
NDIS_UNLOCK(&pCf->Lock);
RSC_WRITE_UNLOCK(&pCf->ClientSync, irql);
TRACE(REGISTER, GPC_STATUS_RESOURCES, 0, "GpcRegisterClient==>");
StatInc(RejectedCf);
return GPC_STATUS_NO_MEMORY;
}
//
// assign a new index to the client. This will also mark the index
// as busy for this CF.
//
pClient->AssignedIndex = AssignNewClientIndex(pCf);
if (pClient->AssignedIndex == (-1)) {
//
// too many clients
//
StatInc(RejectedCf);
NDIS_UNLOCK(&pCf->Lock);
RSC_WRITE_UNLOCK(&pCf->ClientSync, irql);
ReleaseClientBlock(pClient);
TRACE(REGISTER, GPC_STATUS_TOO_MANY_HANDLES, 0, "GpcRegisterClient==>");
return GPC_STATUS_TOO_MANY_HANDLES;
}
//
// init the client block
//
pClient->pCfBlock = pCf;
pClient->ClientCtx = ClientContext;
pClient->Flags = Flags;
pClient->State = GPC_STATE_READY;
if (pClientFuncList) {
RtlMoveMemory(&pClient->FuncList,
pClientFuncList,
sizeof(GPC_CLIENT_FUNC_LIST));
}
//
// add the client block to the CF and update CF
//
GpcInsertTailList(&pCf->ClientList, &pClient->ClientLinkage);
pCf->NumberOfClients++;
//
// fill the output client handle
//
*pClientHandle = (GPC_CLIENT_HANDLE)pClient;
//
// release the lock
//
NDIS_UNLOCK(&pCf->Lock);
RSC_WRITE_UNLOCK(&pCf->ClientSync, irql);
#if 0
//
// if this is not the first client for the CF, start a working
// thread to notify the client about each installed blob for the CF.
// In the call include:
//
if (!IsListEmpty(&pCf->BlobList)) {
//
// this is not the first client, start a notification thread
//
}
#endif
TRACE(REGISTER, pClient, Status, "GpcRegisterClient==>");
if (NT_SUCCESS(Status)) {
StatInc(CreatedCf);
StatInc(CurrentCf);
} else {
StatInc(RejectedCf);
}
return Status;
}
/*
************************************************************************
GpcDeregisterClient -
Deregisters the client and remove associated data from the GPC.
Arguments
ClientHandle - client handle
Returns
GPC_STATUS
************************************************************************
*/
GPC_STATUS
GpcDeregisterClient(
IN GPC_HANDLE ClientHandle
)
{
GPC_STATUS Status = STATUS_SUCCESS;
PCLIENT_BLOCK pClient;
PCF_BLOCK pCf;
TRACE(REGISTER, ClientHandle, 0, "GpcDeregisterClient");
pClient = (PCLIENT_BLOCK)ClientHandle;
NDIS_LOCK(&pClient->Lock);
pCf = pClient->pCfBlock;
if (!IsListEmpty(&pClient->BlobList)) {
Status = GPC_STATUS_NOT_EMPTY;
NDIS_UNLOCK(&pClient->Lock);
return Status;
}
if (pClient->State != GPC_STATE_READY) {
//
// HUH?!?
// Client called to remove twice! probably caller bug
// but we need to protect our selves.
//
NDIS_UNLOCK(&pClient->Lock);
TRACE(REGISTER, GPC_STATUS_NOTREADY, 0, "GpcDeregisterClient==>");
return GPC_STATUS_NOTREADY;
}
//
// remove the client from the Cf's client list
//
pClient->State = GPC_STATE_REMOVE;
pClient->ObjectType = GPC_ENUM_INVALID;
//
// release the client's mapping handle
//
FreeHandle(pClient->ClHandle);
//
// remove the client from the CF list and return the index back
//
#if 0
NDIS_DPR_LOCK(&pCf->Lock);
GpcRemoveEntryList(&pClient->ClientLinkage);
ReleaseClientIndex(pCf->ClientIndexes, pClient->AssignedIndex);
#endif
//
// decrease number of clients
//
if (NdisInterlockedDecrement(&pCf->NumberOfClients) == 0) {
TRACE(CLIENT, pClient, pCf->NumberOfClients, "NumberOfClients");
//
// last client on the CF, we may release all db
//
//UninitializeGenericDb(&pCf->pGenericDb, pCf->MaxPriorities);
}
StatInc(DeletedCf);
StatDec(CurrentCf);
#if 0
NDIS_DPR_UNLOCK(&pCf->Lock);
#endif
NDIS_UNLOCK(&pClient->Lock);
//
// release the client block
//
REFDEL(&pClient->RefCount, 'CLNT');
TRACE(REGISTER, Status, 0, "GpcDeregisterClient==>");
return Status;
}
/*
************************************************************************
GpcAddCfInfo -
Add A new blob. The blob is copied into the GPC and the GPC notifies
other client for the same CF about the installation.
Arguments
ClientHandle - client handle
CfInfoSize - size of the blob
pClientCfInfoPtr - pointer to the blob
ClientCfInfoContext - client's context to associate with the blob
pGpcCfInfoHandle - OUT, returned blob handle
Returns
GPC_STATUS: SUCCESS, PENDING or FAILURE
************************************************************************
*/
GPC_STATUS
GpcAddCfInfo(
IN GPC_HANDLE ClientHandle,
IN ULONG CfInfoSize,
IN PVOID pClientCfInfoPtr,
IN GPC_CLIENT_HANDLE ClientCfInfoContext,
OUT PGPC_HANDLE pGpcCfInfoHandle
)
{
return privateGpcAddCfInfo(ClientHandle,
CfInfoSize,pClientCfInfoPtr,
ClientCfInfoContext,NULL,NULL,
pGpcCfInfoHandle);
}
/*
************************************************************************
PrivateGpcAddCfInfo -
Add A new blob. The blob is copied into the GPC and the GPC notifies
other client for the same CF about the installation.
Arguments
ClientHandle - client handle
CfInfoSize - size of the blob
pClientCfInfoPtr - pointer to the blob
ClientCfInfoContext - client's context to associate with the blob
pGpcCfInfoHandle - OUT, returned blob handle
Returns
GPC_STATUS: SUCCESS, PENDING or FAILURE
************************************************************************
*/
GPC_STATUS
privateGpcAddCfInfo(
IN GPC_HANDLE ClientHandle,
IN ULONG CfInfoSize,
IN PVOID pClientCfInfoPtr,
IN GPC_CLIENT_HANDLE ClientCfInfoContext,
IN PFILE_OBJECT FileObject,
IN PGPC_IP_PATTERN Pattern,
OUT PGPC_HANDLE pGpcCfInfoHandle
)
{
GPC_STATUS Status = GPC_STATUS_SUCCESS;
GPC_STATUS Status1;
PCLIENT_BLOCK pClient;
PCLIENT_BLOCK pNotifyClient;
PCLIENT_BLOCK pNotifyClient2;
PBLOB_BLOCK pBlob;
PCF_BLOCK pCf;
PLIST_ENTRY pEntry, pHead;
int i;
GPC_CLIENT_HANDLE ReturnedCtx;
KIRQL irql;
//If this function fails for any reason we should guarantee that
// Pattern is freed
TRACE(BLOB, ClientHandle, ClientCfInfoContext, "GpcAddCfInfo");
VERIFY_OBJECT_WITH_STATUS(ClientHandle, GPC_ENUM_CLIENT_TYPE,Status);
if(GPC_STATUS_SUCCESS != Status){
if (Pattern){
GpcFreeMem(Pattern,TcpPatternTag);
}
return Status;
}
*pGpcCfInfoHandle = NULL;
//
// cast the client handle to the block
//
pClient = (PCLIENT_BLOCK)ClientHandle;
ASSERT(pClient);
pCf = pClient->pCfBlock;
ASSERT(pCf);
//
// create a new blob block and copy the user data into
//
pBlob = CreateNewBlobBlock(CfInfoSize, pClientCfInfoPtr,IS_USERMODE_CLIENT_EX(pClient));
if (pBlob) {
#if NO_USER_PENDING
//
// this will be only required until we implement the user level
// pending report
//
CTEInitBlockStruc(&pBlob->WaitBlock);
#endif
//
// Put the FileObject and the Pattern information in the Blob.
//
if (FileObject || Pattern)
{
ASSERT(FileObject);
ASSERT(Pattern);
pBlob->FileObject = FileObject;
pBlob->Pattern = Pattern;
}
//
// Add one reference count to the blob since if during
// completion, it might be deleted (if the client fails)
//
REFADD(&pBlob->RefCount, 'ADCF');
//
// set the calling client context inside the blob
//
pBlob->arClientCtx[pClient->AssignedIndex] = ClientCfInfoContext;
//
// set the owner client's context
//
pBlob->OwnerClientCtx = ClientCfInfoContext;
//
// set pointer to installer and the state
//
pBlob->pOwnerClient = pClient;
pBlob->State = GPC_STATE_ADD;
//
// init the client status array to keep track
// of how many client have succeeded so far
//
RtlZeroMemory(pBlob->arpClientStatus, sizeof(pBlob->arpClientStatus));
pBlob->ClientStatusCountDown = 0;
//
// notify each client
//
//NDIS_LOCK(&pCf->Lock);
RSC_READ_LOCK(&pCf->ClientSync, &irql);
pHead = &pCf->ClientList;
pEntry = pHead->Flink;
while (pEntry != pHead && (Status == GPC_STATUS_SUCCESS ||
Status == GPC_STATUS_PENDING)) {
//
// get the notified client block
//
pNotifyClient = CONTAINING_RECORD(pEntry,
CLIENT_BLOCK,
ClientLinkage);
if (pNotifyClient != pClient
&&
!IS_USERMODE_CLIENT(pNotifyClient) ) {
//
// don't notify the caller
//
REFADD(&pNotifyClient->RefCount, 'ADCF');
//
// okay, we have bumped the ref count for this
// client. No need to keep the lock
//
RSC_READ_UNLOCK(&pCf->ClientSync, irql);
//NDIS_UNLOCK(&pCf->Lock);
//
// increase number of count down clients,
// so we keep track how many clients are still
// pending. We do it *before* the call, since
// the completion might be called before the notification
// returns.
//
Status1 = ClientAddCfInfo
(pNotifyClient,
pBlob,
&ReturnedCtx
);
if (Status1 == GPC_STATUS_PENDING) {
pBlob->arClientCtx[pNotifyClient->AssignedIndex] =
ReturnedCtx;
Status = GPC_STATUS_PENDING;
if (pBlob->pNotifiedClient == NULL &&
pNotifyClient->FuncList.ClGetCfInfoName) {
TRACE(BLOB, pBlob, ReturnedCtx, "GpcAddCfInfo: (client)");
//ASSERT(ReturnedCtx);
//
// assume that is the client returned PENDING
// it has some interest in the blob...
//
pBlob->pNotifiedClient = pNotifyClient;
pBlob->NotifiedClientCtx = ReturnedCtx;
}
} else if (!NT_SUCCESS(Status1)) {
//
// some failure, notify each client that reported
// success on the add blob, to remove it
//
//
// change the state to 'remove'
//
pBlob->State = GPC_STATE_REMOVE;
//
// set the last status to the failure status
//
pBlob->LastStatus = Status = Status1;
REFDEL(&pNotifyClient->RefCount, 'ADCF');
for (i = 0; i < MAX_CLIENTS_CTX_PER_BLOB; i++) {
//
// only clients with none zero entries
// have succefully installed the blob
//
if (pNotifyClient = pBlob->arpClientStatus[i]) {
//
// notify each client to remove the blob
//
Status1 = ClientRemoveCfInfo
(
pNotifyClient,
pBlob,
pBlob->arClientCtx[pNotifyClient->AssignedIndex]
);
if (Status1 != GPC_STATUS_PENDING) {
//
// error or success
//
pBlob->arpClientStatus[i] = NULL;
//DereferenceClient(pNotifyClient);
}
}
} // for
//
// don't notify other clients
//
//NDIS_LOCK(&pCf->Lock);
RSC_READ_LOCK(&pCf->ClientSync, &irql);
break;
} else {
//
// status success or ignored reported
//
if (Status1 == GPC_STATUS_SUCCESS) {
pBlob->arClientCtx[pNotifyClient->AssignedIndex] =
ReturnedCtx;
pBlob->arpClientStatus[pNotifyClient->AssignedIndex] =
pNotifyClient;
if (pBlob->pNotifiedClient == NULL &&
pNotifyClient->FuncList.ClGetCfInfoName) {
TRACE(BLOB, pBlob, ReturnedCtx, "GpcAddCfInfo: (client 2)");
//ASSERT(ReturnedCtx);
//
// update the notified client
//
pBlob->pNotifiedClient = pNotifyClient;
pBlob->NotifiedClientCtx = ReturnedCtx;
}
}
}
//
// This is a tricky part,
// we need to let go of the ref count of the current client object
// but get the next one...
//
//NDIS_LOCK(&pCf->Lock);
RSC_READ_LOCK(&pCf->ClientSync, &irql);
pEntry = pEntry->Flink;
if (pEntry != pHead) {
pNotifyClient2 = CONTAINING_RECORD(pEntry,
CLIENT_BLOCK,
ClientLinkage);
REFADD(&pNotifyClient2->RefCount, 'ADCF');
}
//
// release the list lock since the next call will try to get it
//
RSC_READ_UNLOCK(&pCf->ClientSync, irql);
REFDEL(&pNotifyClient->RefCount, 'ADCF');
RSC_READ_LOCK(&pCf->ClientSync, &irql);
if (pEntry != pHead) {
//
// safe to do since the list is locked
//
REFDEL(&pNotifyClient2->RefCount, 'ADCF');
}
} else { // if (pNotifyClient != pClient)
//
// advance to the next client block
//
pEntry = pEntry->Flink;
}
} // while
//
// release the CF lock still got
//
//NDIS_UNLOCK(&pCf->Lock);
RSC_READ_UNLOCK(&pCf->ClientSync, irql);
} else { // if (pBlob)...
//
// error - no more memory?!?
//
// Failed to allocate the blob
// release the pattern memory.
// Must release pattern memory if this function
// fails
if (Pattern){
GpcFreeMem(Pattern,TcpPatternTag);
// Do not access Pattern after
// this
Pattern = NULL;
}
Status = GPC_STATUS_RESOURCES;
}
if (NT_SUCCESS(Status)) {
ASSERT(pBlob);
*pGpcCfInfoHandle = (GPC_CLIENT_HANDLE)pBlob;
if (Status == GPC_STATUS_SUCCESS) {
//
// add the blob to the CF and client lists
//
GpcInterlockedInsertTailList(&pClient->BlobList,
&pBlob->ClientLinkage,
&pClient->Lock
);
GpcInterlockedInsertTailList(&pCf->BlobList,
&pBlob->CfLinkage,
&pCf->Lock
);
pBlob->State = GPC_STATE_READY;
}
} else {
//
// failed - remove the blob
//
if (pBlob)
REFDEL(&pBlob->RefCount, 'BLOB');
}
if (pBlob) {
//
// release the first refcount we got up there...
//
REFDEL(&pBlob->RefCount, 'ADCF');
}
TRACE(BLOB, pBlob, Status, "GpcAddCfInfo==>");
if (Status == GPC_STATUS_SUCCESS) {
CfStatInc(pCf->AssignedIndex,CreatedBlobs);
CfStatInc(pCf->AssignedIndex,CurrentBlobs);
} else if (Status != GPC_STATUS_PENDING) {
CfStatInc(pCf->AssignedIndex,RejectedBlobs);
}
return Status;
}
/*
************************************************************************
GpcAddPattern -
This will install a pattern into the GPC database. The pattern is hooked
to a blob. The pattern can be specific or general.
Adding a specific pattern:
It goes into the specific hash table (per protocol block)
....
return a classification handle
Adding general pattern:
It goes into a separate Rhizome per CF and into its priority slot.
....
Arguments
ClientHandle - client handle
ProtocolTemplate - the protocol template ID to use
Pattern - pattern
Mask - patern mask
Priority - pattern priority in case of conflict
GpcCfInfoHandle - associated blob handle
pGpcPatternHandle - OUT, returned pattern handle
pClassificationHandle - OUT, for specific pattern only
Returns
GPC_STATUS
************************************************************************
*/
GPC_STATUS
GpcAddPattern(
IN GPC_HANDLE ClientHandle,
IN ULONG ProtocolTemplate,
IN PVOID Pattern,
IN PVOID Mask,
IN ULONG Priority,
IN GPC_HANDLE GpcCfInfoHandle,
OUT PGPC_HANDLE pGpcPatternHandle,
OUT PCLASSIFICATION_HANDLE pClassificationHandle
)
{
GPC_STATUS Status;
PCLIENT_BLOCK pClient;
PBLOB_BLOCK pBlob;
PPATTERN_BLOCK pPattern, pCreatedPattern;
PGENERIC_PATTERN_DB pGenericDb;
PCLASSIFICATION_BLOCK pCB;
ULONG i;
PUCHAR p;
ULONG Flags;
PPROTOCOL_BLOCK pProtocolBlock;
ULONG CfIndex;
PGPC_IP_PATTERN pIpPattern;
REQUEST_BLOCK Request, *pRequest;
PLIST_ENTRY pLinkage;
TRACE(PATTERN, ClientHandle, Pattern, "GpcAddPattern");
VERIFY_OBJECT(ClientHandle, GPC_ENUM_CLIENT_TYPE);
//VERIFY_OBJECT(GpcCfInfoHandle, GPC_ENUM_CFINFO_TYPE);
ASSERT(pGpcPatternHandle);
ASSERT(pClassificationHandle);
*pGpcPatternHandle = NULL;
*pClassificationHandle = (CLASSIFICATION_HANDLE)0;
//
// NdisInitializeEvent must run at PASSIVE (isnt that sad)
//
RtlZeroMemory(&Request, sizeof(REQUEST_BLOCK));
NdisInitializeEvent(
&Request.RequestEvent
);
//
// cast the client handle to the block
// and the CfInfo handle to a blob block
//
pClient = (PCLIENT_BLOCK)ClientHandle;
pBlob = (PBLOB_BLOCK)GpcCfInfoHandle;
ASSERT(pClient);
CfIndex = pClient->pCfBlock->AssignedIndex;
if (Priority >= pClient->pCfBlock->MaxPriorities ||
ProtocolTemplate >= GPC_PROTOCOL_TEMPLATE_MAX ) {
return GPC_STATUS_INVALID_PARAMETER;
}
if (pBlob != NULL) {
NDIS_LOCK(&pBlob->Lock);
if (pBlob->ObjectType != GPC_ENUM_CFINFO_TYPE) {
NDIS_UNLOCK(&pBlob->Lock);
return GPC_STATUS_INVALID_PARAMETER;
}
}
NDIS_LOCK(&glData.RequestListLock);
if (pBlob != NULL && pBlob->State != GPC_STATE_READY) {
//
// Block until it is safe to restart the work.
//
InsertTailList(&glData.gRequestList, &Request.Linkage);
NDIS_UNLOCK(&glData.RequestListLock);
//
// doing something else
//
NDIS_UNLOCK(&pBlob->Lock);
if (TRUE == NdisWaitEvent(
&Request.RequestEvent,
0
)) {
//
// The wait was successful, continue with regularly scheduled programming.
// This lock needs to be taken when we get out.
NDIS_LOCK(&pBlob->Lock);
} else {
//
// How could this happen? I dont know.
// Definitely need to investigate.
//
TRACE(PATTERN, GPC_STATUS_FAILURE, 0, "GpcAddPattern: The conflict <-> wait <-> resume plan has FAILED!\n");
ASSERT(FALSE);
return GPC_STATUS_NOTREADY;
}
} else {
NDIS_UNLOCK(&glData.RequestListLock);
}
//
// determine if the pattern is specific or generic
//
pProtocolBlock = &glData.pProtocols[ProtocolTemplate];
if (ProtocolTemplate == GPC_PROTOCOL_TEMPLATE_IP) {
//
//
//
pIpPattern = (PGPC_IP_PATTERN)Pattern;
pIpPattern->Reserved[0] = pIpPattern->Reserved[1] = pIpPattern->Reserved[2] = 0;
pIpPattern = (PGPC_IP_PATTERN)Mask;
pIpPattern->Reserved[0] = pIpPattern->Reserved[1] = pIpPattern->Reserved[2] = 0xff;
}
for (i = 0, p=(PUCHAR)Mask; i < pProtocolBlock->PatternSize; i++, p++) {
if (*p != 0xff)
break;
}
//
// set the Flags
//
Flags = (i < pProtocolBlock->PatternSize) ? 0 : PATTERN_SPECIFIC;
if (pBlob != NULL) {
//
// change the blob state to ADD, so no one can delete it
// while the pattern is being added to its list
//
pBlob->State = GPC_STATE_ADD;
NDIS_UNLOCK(&pBlob->Lock);
}
//
// increment ref counting
//
//NdisInterlockedIncrement(&pClient->RefCount);
//
// cerate a new pattern block
//
pPattern = CreateNewPatternBlock(Flags);
pCreatedPattern = pPattern;
#if DBG
{
PGPC_IP_PATTERN pIp = (PGPC_IP_PATTERN)Pattern;
PGPC_IP_PATTERN pMask = (PGPC_IP_PATTERN)Mask;
DBGPRINT(PATTERN, ("GpcAddPattern: Client=%X %s - ",
pClient,
TEST_BIT_ON(Flags, PATTERN_SPECIFIC)?"Specific":"Generic"));
DBGPRINT(PATTERN, ("IP: ifc={%d,%d} src=%08X:%04x, dst=%08X:%04x, prot=%d rsv=%x,%x,%x\n",
pIp->InterfaceId.InterfaceId,
pIp->InterfaceId.LinkId,
pIp->SrcAddr,
pIp->gpcSrcPort,
pIp->DstAddr,
pIp->gpcDstPort,
pIp->ProtocolId,
pIp->Reserved[0],
pIp->Reserved[1],
pIp->Reserved[2]
));
DBGPRINT(PATTERN, ("Mask: ifc={%x,%x} src=%08X:%04x, dst=%08X:%04x, prot=%x rsv=%x,%x,%x\n",
pMask->InterfaceId.InterfaceId,
pMask->InterfaceId.LinkId,
pMask->SrcAddr,
pMask->gpcSrcPort,
pMask->DstAddr,
pMask->gpcDstPort,
pMask->ProtocolId,
pMask->Reserved[0],
pMask->Reserved[1],
pMask->Reserved[2]
));
}
#endif
if (pPattern) {
//
// add one reference count to the pattern, so when we add it
// to the db, we're sure it stays there
//
//pPattern->RefCount++;
pPattern->Priority = Priority;
pPattern->ProtocolTemplate = ProtocolTemplate;
if (TEST_BIT_ON(Flags, PATTERN_SPECIFIC)) {
//
// add a specific pattern
//
Status = AddSpecificPattern(
pClient,
Pattern,
Mask,
pBlob,
pProtocolBlock,
&pPattern, // output pattern pointer
pClassificationHandle
);
} else {
//
// add a generic pattern
//
Status = AddGenericPattern(
pClient,
Pattern,
Mask,
Priority,
pBlob,
pProtocolBlock,
&pPattern // output pattern pointer
);
}
// [OferBar]
// release the extra ref count that was added
// in the case of a specific pattern, this might be a totally different
// one, but it should still have the extra ref-count
// if there was an error, this will release the pattern
// REFDEL(&pPattern->RefCount, 'FILT');
// [ShreeM]
// A reference FILT is added to a filter on creation. This will be substituted by 'ADSP' or
// 'ADGP' whether it was a Generic Pattern or a Specific Pattern. However, it is likely that
// in the AddSpecificPattern function, the pPattern got changed to something else because a
// filter already existed. We want to ensure that the tag subsitution happens only in the
// case where pPattern was not replaced with the existing pattern in AddSpecificPattern.
//
REFDEL(&pCreatedPattern->RefCount, 'FILT');
//
// check if failure, and if so - release the pattern block
//
if (NT_SUCCESS(Status)) {
//
// fill the output handle
//
*pGpcPatternHandle = (GPC_HANDLE)pPattern;
}
} else {
Status = GPC_STATUS_RESOURCES;
}
if (pBlob != NULL) {
//
// change the state back to ready, so others can work on this blob
//
pBlob->State = GPC_STATE_READY;
}
//
// release the extra ref count
//
//NdisInterlockedDecrement(&pClient->RefCount);
TRACE(PATTERN, pPattern, Status, "GpcAddPattern==>");
if (NT_SUCCESS(Status)) {
if (TEST_BIT_ON(Flags, PATTERN_SPECIFIC)) {
ProtocolStatInc(ProtocolTemplate,
CreatedSp);
ProtocolStatInc(ProtocolTemplate,
CurrentSp);
NdisInterlockedIncrement(&pProtocolBlock->SpecificPatternCount);
ASSERT(pProtocolBlock->SpecificPatternCount > 0);
} else {
ProtocolStatInc(ProtocolTemplate,
CreatedGp);
ProtocolStatInc(ProtocolTemplate,
CurrentGp);
NdisInterlockedIncrement(&pProtocolBlock->GenericPatternCount);
ASSERT(pProtocolBlock->GenericPatternCount > 0);
}
} else {
if (TEST_BIT_ON(Flags, PATTERN_SPECIFIC)) {
ProtocolStatInc(ProtocolTemplate,
RejectedSp);
} else {
ProtocolStatInc(ProtocolTemplate,
RejectedGp);
}
}
//
// Check if some requests got queued while we were in there.
//
ASSERT(KeGetCurrentIrql() < DISPATCH_LEVEL);
NDIS_LOCK(&glData.RequestListLock);
if (!IsListEmpty(&glData.gRequestList)) {
pLinkage = RemoveHeadList(&glData.gRequestList);
NDIS_UNLOCK(&glData.RequestListLock);
pRequest = CONTAINING_RECORD(pLinkage, REQUEST_BLOCK, Linkage);
NdisSetEvent(&pRequest->RequestEvent);
} else {
NDIS_UNLOCK(&glData.RequestListLock);
}
return Status;
}
/*
************************************************************************
GpcAddCfInfoNotifyComplete -
A completion routine that the client will call after the GPC called into
the client's ClAddCfInfoNotify handler, but returned PENDING.
After all the clients have completed, a callback to the calling client's
ClAddCfInfoComplete is done to complete the GpcAddCfInfo call.
Arguments
ClientHandle - client handle
GpcCfInfoHandle - the blob handle
Status - completion status
Returns
void
************************************************************************
*/
VOID
GpcAddCfInfoNotifyComplete(
IN GPC_HANDLE ClientHandle,
IN GPC_HANDLE GpcCfInfoHandle,
IN GPC_STATUS Status,
IN GPC_CLIENT_HANDLE ClientCfInfoContext
)
{
PCLIENT_BLOCK pClient, pNotifyClient, pFirstClient;
PBLOB_BLOCK pBlob;
//GPC_CLIENT_HANDLE ClientCtx;
//ULONG cd;
int i;
GPC_STATUS LastStatus, Status1;
TRACE(BLOB, GpcCfInfoHandle, Status, "GpcAddCfInfoNotifyComplete");
//VERIFY_OBJECT(ClientHandle, GPC_ENUM_CLIENT_TYPE);
//VERIFY_OBJECT(GpcCfInfoHandle, GPC_ENUM_CFINFO_TYPE);
pClient = (PCLIENT_BLOCK)ClientHandle;
pBlob = (PBLOB_BLOCK)GpcCfInfoHandle;
ASSERT(pBlob);
ASSERT(pClient);
ASSERT(Status != GPC_STATUS_PENDING);
ASSERT(pBlob->ClientStatusCountDown > 0);
if (NT_SUCCESS(Status)) {
//
// success reported, save the reporting client handle
// so we can notify him to remove the blob in case of an error
// down the road by another client for the same blob
//
ASSERT(pBlob->arpClientStatus[pClient->AssignedIndex] == NULL);
pBlob->arpClientStatus[pClient->AssignedIndex] = pClient;
} else {
//
// error reported, update the last status code.
//
pBlob->LastStatus = Status;
}
if (NdisInterlockedDecrement(&pBlob->ClientStatusCountDown) == 0) {
//
// all clients have reported
//
//
// save the client's blob data, cuz it might get deleted
//
//ClientCtx = pBlob->arClientCtx[pClient->AssignedIndex];
LastStatus = pBlob->LastStatus;
pFirstClient = pBlob->pOwnerClient;
if (NT_ERROR(LastStatus)) {
//
// error has been previously reported by a client
// tell each client that reported success to remove
// the blob (sorry...)
//
#if 0
NDIS_LOCK(&pBlob->pOwnerClient->pCfBlock->Lock);
GpcRemoveEntryList(&pBlob->CfLinkage);
NDIS_DPR_LOCK(&pBlob->pOwnerClient->Lock);
GpcRemoveEntryList(&pBlob->ClientLinkage);
NDIS_DPR_UNLOCK(&pBlob->pOwnerClient->Lock);
NDIS_UNLOCK(&pBlob->pOwnerClient->pCfBlock->Lock);
#endif
CTEInitBlockStruc(&pBlob->WaitBlockAddFailed);
Status1 = GPC_STATUS_SUCCESS;
for (i = 0; i < MAX_CLIENTS_CTX_PER_BLOB; i++) {
//
// only clients with none zero entries
// have succefully installed the blob
//
if (pNotifyClient = pBlob->arpClientStatus[i]) {
//
// notify each client to remove the blob
//
if (ClientRemoveCfInfo
(
pNotifyClient,
pBlob,
pBlob->arClientCtx[pNotifyClient->AssignedIndex]
) == GPC_STATUS_PENDING)
{
Status1 = GPC_STATUS_PENDING;
} else {
//DereferenceClient(pNotifyClient);
}
}
} // for
if (Status1 == GPC_STATUS_PENDING) {
//
// Block on completion of all removals...
//
Status1 = CTEBlock(&pBlob->WaitBlockAddFailed);
}
} else { // if (NT_ERROR(LastStats))...
//
// store the returned client context, since the call can be completed
// before the notification handler returns.
//
pBlob->arClientCtx[pClient->AssignedIndex] = ClientCfInfoContext;
//
// add the blob to the CF and client lists
//
GpcInterlockedInsertTailList(&pBlob->pOwnerClient->BlobList,
&pBlob->ClientLinkage,
&pBlob->pOwnerClient->Lock
);
GpcInterlockedInsertTailList(&pBlob->pOwnerClient->pCfBlock->BlobList,
&pBlob->CfLinkage,
&pBlob->pOwnerClient->pCfBlock->Lock
);
}
//
// complete the request to the client
//
ClientAddCfInfoComplete(
pFirstClient, // first guy who made the call
pBlob, // completing blob
LastStatus // status
);
}
//
// this will be done after the last client completes
//
//DereferenceClient(pClient);
}
/*
************************************************************************
GpcModifyCfInfo -
The client calls this to modify a blob. Each other client on the CF will
get notified. This routine returns PENDING and starts a working thread
to do the main job.
Arguments
ClientHandle - client handle
GpcCfInfoHandle - the handle of the blob to modify
CfInfoSize - new blob size
pClientCfInfo - new blob data pointer
Returns
GPC_STATUS, PENDING is valid
************************************************************************
*/
GPC_STATUS
GpcModifyCfInfo(
IN GPC_HANDLE ClientHandle,
IN GPC_HANDLE GpcCfInfoHandle,
IN ULONG CfInfoSize,
IN PVOID pClientCfInfoPtr
)
{
GPC_STATUS Status = GPC_STATUS_SUCCESS;
GPC_STATUS Status1;
PCLIENT_BLOCK pClient;
PCLIENT_BLOCK pNotifyClient;
PCLIENT_BLOCK pNotifyClient2;
PBLOB_BLOCK pBlob;
PCF_BLOCK pCf;
PLIST_ENTRY pEntry, pHead;
int i;
KIRQL irql;
TRACE(BLOB, ClientHandle, GpcCfInfoHandle, "GpcModifyCfInfo");
VERIFY_OBJECT(ClientHandle, GPC_ENUM_CLIENT_TYPE);
//VERIFY_OBJECT(GpcCfInfoHandle, GPC_ENUM_CFINFO_TYPE);
ASSERT(pClientCfInfoPtr);
//
// cast the client handle to the block
//
pClient = (PCLIENT_BLOCK)ClientHandle;
pBlob = (PBLOB_BLOCK)GpcCfInfoHandle;
pCf = pClient->pCfBlock;
ASSERT(pClient);
ASSERT(pBlob);
NDIS_LOCK(&pBlob->Lock);
if (pBlob->ObjectType != GPC_ENUM_CFINFO_TYPE) {
NDIS_UNLOCK(&pBlob->Lock);
return GPC_STATUS_INVALID_PARAMETER;
}
//
// check the blob is in READY state and change it to MODIFY state
//
if (pBlob->State != GPC_STATE_READY) {
NDIS_UNLOCK(&pBlob->Lock);
return GPC_STATUS_NOTREADY;
}
//
// allocate private memory in the GPC to copy the client's data
// into
//
GpcAllocMem(&pBlob->pNewClientData, CfInfoSize, CfInfoDataTag);
if (pBlob->pNewClientData == NULL) {
NDIS_UNLOCK(&pBlob->Lock);
return GPC_STATUS_RESOURCES;
}
pBlob->NewClientDataSize = CfInfoSize;
pBlob->State = GPC_STATE_MODIFY;
//
// we set the calling client here so we can notify it when the
// the modification is completed
//
pBlob->pCallingClient = pClient;
NDIS_UNLOCK(&pBlob->Lock);
#if NO_USER_PENDING
//
// this will be only required until we implement the user level
// pending report
//
CTEInitBlockStruc(&pBlob->WaitBlock);
#endif
//
// copy the memory
//
RtlMoveMemory(pBlob->pNewClientData, pClientCfInfoPtr, CfInfoSize);
//
// init the client status array to keep track
// of how many client have succeeded so far
//
//RtlZeroMemory(pBlob->arpClientStatus, sizeof(pBlob->arpClientStatus));
pBlob->ClientStatusCountDown = 0;
pBlob->LastStatus = GPC_STATUS_SUCCESS;
//
// notify each client
//
//NDIS_LOCK(&pCf->Lock);
RSC_READ_LOCK(&pCf->ClientSync, &irql);
pHead = &pCf->ClientList;
pEntry = pHead->Flink;
while (pEntry != pHead && (Status == GPC_STATUS_SUCCESS ||
Status == GPC_STATUS_PENDING)) {
//
// get the notified client block
//
pNotifyClient = CONTAINING_RECORD(pEntry, CLIENT_BLOCK, ClientLinkage);
if (pNotifyClient != pClient
&&
pBlob->arpClientStatus[pNotifyClient->AssignedIndex]
&&
!IS_USERMODE_CLIENT(pNotifyClient) ) {
//
// don't notify the caller
//
REFADD(&pNotifyClient->RefCount, 'CFMF');
//
// okay, we have bumped the ref count for this
// client. No need to keep the lock
//
//NDIS_UNLOCK(&pCf->Lock);
RSC_READ_UNLOCK(&pCf->ClientSync, irql);
//
// increase number of count down clients,
// so we keep track how many clients are still
// pending. We do it *before* the call, since
// the completion might be called before the notification
// returns.
//
Status1 = ClientModifyCfInfo
(pNotifyClient,
pBlob,
CfInfoSize,
pBlob->pNewClientData
);
TRACE(BLOB, pBlob, Status1, "GpcModifyCfInfo: (client)");
//
// grab the lock again since we're walking the list
//
//NDIS_LOCK(&pCf->Lock);
//
// now we check the Status1 code
// the rules are:
// we stop on failure
// ignore GPC_STATUS_IGNORE
// and save PENDING status
//
if (Status1 == GPC_STATUS_PENDING
&&
!NT_SUCCESS(pBlob->LastStatus)) {
//
// we've got back pending, but the client
// actually completed the request
// behind our back
//
Status = GPC_STATUS_PENDING;
REFDEL(&pNotifyClient->RefCount, 'CFMF');
RSC_READ_LOCK(&pCf->ClientSync, &irql);
break;
} else if (!NT_SUCCESS(Status1)) {
//
// don't notify other clients
//
pBlob->LastStatus = Status = Status1;
REFDEL(&pNotifyClient->RefCount, 'CFMF');
RSC_READ_LOCK(&pCf->ClientSync, &irql);
break;
} else if (Status1 == GPC_STATUS_SUCCESS
||
Status1 == GPC_STATUS_PENDING) {
pBlob->arpClientStatus[pNotifyClient->AssignedIndex] =
pNotifyClient;
if (Status1 == GPC_STATUS_PENDING) {
Status = GPC_STATUS_PENDING;
}
}
RSC_READ_LOCK(&pCf->ClientSync, &irql);
pEntry = pEntry->Flink;
if (pEntry != pHead) {
pNotifyClient2 = CONTAINING_RECORD(pEntry,
CLIENT_BLOCK,
ClientLinkage);
REFADD(&pNotifyClient2->RefCount, 'CFMF');
}
//
// release the list lock since the next call will try to get it
//
RSC_READ_UNLOCK(&pCf->ClientSync, irql);
REFDEL(&pNotifyClient->RefCount, 'CFMF');
RSC_READ_LOCK(&pCf->ClientSync, &irql);
if (pEntry != pHead) {
//
// safe to do since the list is locked
//
REFDEL(&pNotifyClient2->RefCount, 'CFMF');
}
} else { // if (pNotifyClient != pClient)
//
// grab the next client block,
//
pEntry = pEntry->Flink;
}
} // while
//
// release the CF lock still got
//
//NDIS_UNLOCK(&pCf->Lock);
RSC_READ_UNLOCK(&pCf->ClientSync, irql);
//
// Status code should be either:
//
// GPC_STATUS_SUCCESS - all clients have been notified and returned SUCCESS
// GPC_STATUS_PENDING - all clients have been notified, at least one
// return PENDING
// Error code - at least one client failed
//
if (Status != GPC_STATUS_PENDING) {
//
// Note: the status here can be either FAILED or SUCCESS
//
// no client has been pending, so we complete the modification
// back to the clients (except the caling client)
//
ModifyCompleteClients(pClient, pBlob);
//
// restore READY state
//
pBlob->State = GPC_STATE_READY;
}
TRACE(BLOB, pBlob, Status, "GpcModifyCfInfo==>");
if (NT_SUCCESS(Status)) {
CfStatInc(pCf->AssignedIndex,ModifiedBlobs);
}
return Status;
}
/*
************************************************************************
GpcModifyCfInfoNotifyComplete -
Called by clients to complete a previous call to ClModifyCfInfoNotify
made by the GPC.
Arguments
ClientHandle - client handle
GpcCfInfoHandle - the blob handle
Status - completion status
Returns
GPC_STATUS
************************************************************************
*/
VOID
GpcModifyCfInfoNotifyComplete(
IN GPC_HANDLE ClientHandle,
IN GPC_HANDLE GpcCfInfoHandle,
IN GPC_STATUS Status
)
{
PCLIENT_BLOCK pClient, pNotifyClient;
PBLOB_BLOCK pBlob;
TRACE(BLOB, GpcCfInfoHandle, Status, "GpcModifyCfInfoNotifyComplete");
//VERIFY_OBJECT(ClientHandle, GPC_ENUM_CLIENT_TYPE);
//VERIFY_OBJECT(GpcCfInfoHandle, GPC_ENUM_CFINFO_TYPE);
pClient = (PCLIENT_BLOCK)ClientHandle;
pBlob = (PBLOB_BLOCK)GpcCfInfoHandle;
ASSERT(pBlob);
ASSERT(pClient);
ASSERT(Status != GPC_STATUS_PENDING);
ASSERT(pBlob->ClientStatusCountDown > 0);
if (NT_SUCCESS(Status)) {
//
// success reported, save the reporting client handle
// so we can notify him to remove the blob in case of an error
// down the road by another client for the same blob
//
ASSERT(pBlob->arpClientStatus[pClient->AssignedIndex] == pClient);
//pBlob->arpClientStatus[pClient->AssignedIndex] = pClient;
} else {
//
// error reported, update the last status code.
//
pBlob->LastStatus = Status;
}
if (NdisInterlockedDecrement(&pBlob->ClientStatusCountDown) == 0) {
//
// all clients have reported
//
ModifyCompleteClients(pClient, pBlob);
#if NO_USER_PENDING
//
// the user is blocking on this call
//
CTESignal(&pBlob->WaitBlock, Status);
#else
//
// now, complete the call back to the calling client
//
ClientModifyCfInfoComplete(
pBlob->pCallingClient,
pBlob,
pBlob->LastStatus
);
pBlob->State = GPC_STATE_READY;
#endif
}
TRACE(BLOB, pClient, Status, "GpcModifyCfInfoNotifyComplete==>");
}
/*
************************************************************************
privateGpcRemoveCfInfo -
Remove a blob from GPC.
Arguments
ClientHandle - client handle
GpcCfInfoHandle - blob handle
Returns
GPC_STATUS
************************************************************************
*/
GPC_STATUS
privateGpcRemoveCfInfo(
IN GPC_HANDLE ClientHandle,
IN GPC_HANDLE GpcCfInfoHandle,
IN ULONG Flags
)
{
GPC_STATUS Status = GPC_STATUS_SUCCESS;
GPC_STATUS Status1;
PCLIENT_BLOCK pClient;
PCLIENT_BLOCK pNotifyClient;
PCLIENT_BLOCK pNotifyClient2;
PBLOB_BLOCK pBlob;
PCF_BLOCK pCf;
PPATTERN_BLOCK pPattern;
PLIST_ENTRY pHead, pEntry;
KIRQL irql;
PPROTOCOL_BLOCK pProtocol;
ULONG cClientRef;
TRACE(BLOB, ClientHandle, GpcCfInfoHandle, "privateGpcRemoveCfInfo");
VERIFY_OBJECT(ClientHandle, GPC_ENUM_CLIENT_TYPE);
pClient = (PCLIENT_BLOCK)ClientHandle;
pBlob = (PBLOB_BLOCK)GpcCfInfoHandle;
pCf = pClient->pCfBlock;
NDIS_LOCK(&pBlob->Lock);
if (pBlob->ObjectType != GPC_ENUM_CFINFO_TYPE) {
NDIS_UNLOCK(&pBlob->Lock);
return GPC_STATUS_INVALID_PARAMETER;
}
if (pBlob->State != GPC_STATE_READY) {
if ((pBlob->pCallingClient2) || (IS_USERMODE_CLIENT_EX(pClient))){
//
// Can't handle more than 2 removals for the
// same flow.
// another client has already requested the removal of
// this flow, we should fail here
//
// Also dont pend requests from user mode clients using the new IOCTL
// interface
NDIS_UNLOCK(&pBlob->Lock);
TRACE(BLOB, GPC_STATUS_NOTREADY, 0, "privateGpcRemoveCfInfo==>");
return GPC_STATUS_NOTREADY;
}
//
// the flow is being removed when another client
// requested its removal. we save this client handle
// and we'll coplete it later
//
pBlob->pCallingClient2 = pClient;
NDIS_UNLOCK(&pBlob->Lock);
TRACE(BLOB, GPC_STATUS_PENDING, 0, "privateGpcRemoveCfInfo==>");
return GPC_STATUS_PENDING;
}
//
// remove the supported patterns on the cfinfo
// there are two cases:
//
// 1. from a user - traffic.dll requires that ALL the filters
// would have been deleted, therefore this case is a nop.
//
// 2. from a kernel client - in this case we MUST remove the
// patterns before proceesing to delete the cfinfo,
// since we can't rely on traffic.dll to do it
//
//
// grab a refcount on this blob so it doesn't go away due
// to some funky client that decides to complete before
// it return any status code (and most of them do!)
// this should be released before we exit the routine,
// so that the blob may actually go away on the last deref
//
REFADD(&pBlob->RefCount, 'RMCF');
//
// set the removing client
//
pBlob->pCallingClient = pClient;
//
// don't allow the user mode owner client to remove this flow
// if there are any patterns on it....
// ...unless the REMOVE_CB_BLOB bit ahs been set,
// for example: when the calling process dies
//
if (!IsListEmpty(&pBlob->PatternList) &&
TEST_BIT_ON(pClient->Flags, GPC_FLAGS_USERMODE_CLIENT) &&
(pClient == pBlob->pOwnerClient) &&
TEST_BIT_OFF(pBlob->Flags, PATTERN_REMOVE_CB_BLOB)
)
{
NDIS_UNLOCK(&pBlob->Lock);
return GPC_STATUS_NOT_EMPTY;
} else {
//
// Since we have decided to remove the patterns, we should
// mark this as invalid
//
pBlob->ObjectType = GPC_ENUM_INVALID;
}
while (!IsListEmpty(&pBlob->PatternList)) {
pPattern = CONTAINING_RECORD(pBlob->PatternList.Flink,
PATTERN_BLOCK,
BlobLinkage[pCf->AssignedIndex]);
NDIS_DPR_LOCK(&pPattern->Lock);
REFADD(&pPattern->RefCount, 'RMCF');
pPattern->State = GPC_STATE_FORCE_REMOVE;
//
// If it is an AUTO PATTERN, remove it from the list and
// unset the flag.
//
if (TEST_BIT_ON( pPattern->Flags, PATTERN_AUTO)) {
pProtocol = &glData.pProtocols[pPattern->ProtocolTemplate];
pPattern->Flags |= ~PATTERN_AUTO;
NDIS_DPR_LOCK(&pProtocol->PatternTimerLock[pPattern->WheelIndex]);
GpcRemoveEntryList(&pPattern->TimerLinkage);
NDIS_DPR_UNLOCK(&pProtocol->PatternTimerLock[pPattern->WheelIndex]);
InitializeListHead(&pPattern->TimerLinkage);
NDIS_DPR_UNLOCK(&pPattern->Lock);
NDIS_UNLOCK(&pBlob->Lock);
privateGpcRemovePattern(ClientHandle, (GPC_HANDLE)pPattern, TRUE, FALSE);
InterlockedDecrement(&pProtocol->AutoSpecificPatternCount);
} else {
NDIS_DPR_UNLOCK(&pPattern->Lock);
NDIS_UNLOCK(&pBlob->Lock);
}
privateGpcRemovePattern(ClientHandle, (GPC_HANDLE)pPattern, TRUE , FALSE);
REFDEL(&pPattern->RefCount, 'RMCF');
NDIS_LOCK(&pBlob->Lock);
}
//
// set the state
//
pBlob->State = GPC_STATE_REMOVE;
NDIS_UNLOCK(&pBlob->Lock);
#if NO_USER_PENDING
//
// this will be only required until we implement the user level
// pending report
//
CTEInitBlockStruc(&pBlob->WaitBlock);
#endif
SuspendHandle(pBlob->ClHandle);
//
// init the client status array to keep track
// of how many client have succeeded so far
//
//RtlZeroMemory(pBlob->arpClientStatus, sizeof(pBlob->arpClientStatus));
pBlob->ClientStatusCountDown = 0;
pBlob->LastStatus = GPC_STATUS_SUCCESS;
//
// notify each client
//
NDIS_LOCK(&pCf->Lock);
GpcRemoveEntryList(&pBlob->CfLinkage);
NDIS_UNLOCK(&pCf->Lock);
//NDIS_LOCK(&pClient->Lock);
RSC_READ_LOCK(&pCf->ClientSync, &irql);
NDIS_LOCK(&pClient->Lock);
GpcRemoveEntryList(&pBlob->ClientLinkage);
NDIS_UNLOCK(&pClient->Lock);
//NDIS_UNLOCK(&pClient->Lock);
//
// the blob is not on the CF or on the client list
// okay to change the object type so further handle lookup will fail
//
pHead = &pCf->ClientList;
pEntry = pHead->Flink;
while (pEntry != pHead && (Status == GPC_STATUS_SUCCESS ||
Status == GPC_STATUS_PENDING)) {
//
// get the notified client block
//
pNotifyClient = CONTAINING_RECORD(pEntry, CLIENT_BLOCK, ClientLinkage);
if (pNotifyClient != pClient
&&
pBlob->arpClientStatus[pNotifyClient->AssignedIndex] ) {
//
// don't notify the caller
//
REFADD(&pNotifyClient->RefCount, 'PRCF');
//NDIS_UNLOCK(&pCf->Lock);
RSC_READ_UNLOCK(&pCf->ClientSync, &irql);
Status1 = ClientRemoveCfInfo
(pNotifyClient,
pBlob,
pBlob->arClientCtx[pNotifyClient->AssignedIndex]
);
TRACE(BLOB, pBlob, Status, "privateGpcRemoveCfInfo: (client)");
RSC_READ_LOCK(&pCf->ClientSync, &irql);
if (Status1 == GPC_STATUS_PENDING) {
Status = GPC_STATUS_PENDING;
} else {
if (NT_ERROR(Status1)) {
Status = pBlob->LastStatus = Status1;
} else {
//
// status success
//
pBlob->arpClientStatus[pNotifyClient->AssignedIndex] =
pNotifyClient;
NDIS_DPR_LOCK(&pBlob->Lock);
if (pNotifyClient == pBlob->pNotifiedClient) {
pBlob->pNotifiedClient = NULL;
pBlob->NotifiedClientCtx = NULL;
}
NDIS_DPR_UNLOCK(&pBlob->Lock);
}
//
// not pending - no need to hold the ref count to this client
//
//DereferenceClient(pNotifyClient);
}
//
// advance to the next client block, and release the ref count
// for this client
//
//NDIS_LOCK(&pCf->Lock);
pEntry = pEntry->Flink;
if (pEntry != pHead) {
pNotifyClient2 = CONTAINING_RECORD(pEntry,
CLIENT_BLOCK,
ClientLinkage);
REFADD(&pNotifyClient2->RefCount, 'PRCF');
}
//
// release the list lock since the next call will try to get it
//
RSC_READ_UNLOCK(&pCf->ClientSync, irql);
REFDEL(&pNotifyClient->RefCount, 'PRCF');
RSC_READ_LOCK(&pCf->ClientSync, &irql);
if (pEntry != pHead) {
//
// safe to do since the list is locked
//
REFDEL(&pNotifyClient2->RefCount, 'PRCF');
}
} else { // if (pNotifyClient != pClient)
pEntry = pEntry->Flink;
}
} // while
//NDIS_UNLOCK(&pCf->Lock);
RSC_READ_UNLOCK(&pCf->ClientSync, irql);
if (Status != GPC_STATUS_PENDING) {
NDIS_LOCK(&pBlob->Lock);
//
// notify any pending client about the status
//
if (pClient = pBlob->pCallingClient2) {
pClient = pBlob->pCallingClient2;
pBlob->pCallingClient2 = NULL;
NDIS_UNLOCK(&pBlob->Lock);
//
// complete the request to this client
//
ClientRemoveCfInfoComplete
(
pClient, // the guy who made the call
pBlob, // completing blob
Status // status
);
//pBlob->pCallingClient2 = NULL;
} else {
NDIS_UNLOCK(&pBlob->Lock);
}
if (Status != GPC_STATUS_SUCCESS) {
//
// failed to remove the blob
//
pBlob->State = GPC_STATE_READY;
pBlob->ObjectType = GPC_ENUM_CFINFO_TYPE;
//
// resume the suspended handle
//
ResumeHandle(pBlob->ClHandle);
}
}
if (Status == GPC_STATUS_SUCCESS) {
//
// release the mapping handle
//
FreeHandle(pBlob->ClHandle);
//
// all done, we can remove the blob from memory
//
REFDEL(&pBlob->RefCount, 'BLOB');
CfStatInc(pCf->AssignedIndex,DeletedBlobs);
CfStatDec(pCf->AssignedIndex,CurrentBlobs);
}
//
// release the extra refcount we got in the begining
// this is to avoid the problem of the blob going away,
// since some clients may complete the remove before we get
// here, and this will cause the blob structure to be released
// it's not a pretty sight....
//
REFDEL(&pBlob->RefCount, 'RMCF');
TRACE(BLOB, Status, 0, "privateGpcRemoveCfInfo==>");
return Status;
}
/*
************************************************************************
GpcRemoveCfInfo -
This must have been called from kernel. We simply pass the call
to the private routine with Flags=0.
Arguments
ClientHandle - client handle
GpcCfInfoHandle - blob handle
Returns
GPC_STATUS
************************************************************************
*/
GPC_STATUS
GpcRemoveCfInfo(
IN GPC_HANDLE ClientHandle,
IN GPC_HANDLE GpcCfInfoHandle
)
{
return privateGpcRemoveCfInfo(
ClientHandle,
GpcCfInfoHandle,
0
);
}
/*
************************************************************************
GpcRemoveCfInfoNotifyComplete -
Called by clients who are completing a ClRemoveCfInfoNotify that was PENDING.
This may have been called for two reasons:
1. A client issued a GpcRemoveCfInfo request.
2. A client issued a GpcAddCfInfo request, but one of the other clients
failed, so we are removing the successfully installed blobs.
Arguments
ClientHandle - client handle
GpcCfInfoHandle - the blob handle
Status - completion status
Returns
void
************************************************************************
*/
VOID
GpcRemoveCfInfoNotifyComplete(
IN GPC_HANDLE ClientHandle,
IN GPC_HANDLE GpcCfInfoHandle,
IN GPC_STATUS Status
)
{
PCLIENT_BLOCK pClient;
PBLOB_BLOCK pBlob;
PCLIENT_BLOCK pClient2;
TRACE(BLOB, GpcCfInfoHandle, Status, "GpcRemoveCfInfoNotifyComplete");
//VERIFY_OBJECT(ClientHandle, GPC_ENUM_CLIENT_TYPE);
//VERIFY_OBJECT(GpcCfInfoHandle, GPC_ENUM_CFINFO_TYPE);
pClient = (PCLIENT_BLOCK)ClientHandle;
pBlob = (PBLOB_BLOCK)GpcCfInfoHandle;
ASSERT(pBlob);
ASSERT(pClient);
ASSERT(Status != GPC_STATUS_PENDING);
ASSERT(pBlob->ClientStatusCountDown > 0);
if (!NT_ERROR(pBlob->LastStatus) || NT_ERROR(Status)) {
//
// save the last error code
//
pBlob->LastStatus = Status;
}
NDIS_LOCK(&pBlob->Lock);
if (Status == GPC_STATUS_SUCCESS && pClient == pBlob->pNotifiedClient) {
pBlob->pNotifiedClient = NULL;
pBlob->NotifiedClientCtx = NULL;
}
NDIS_UNLOCK(&pBlob->Lock);
if (NdisInterlockedDecrement(&pBlob->ClientStatusCountDown) == 0) {
if (pBlob->State == GPC_STATE_REMOVE) {
if (pBlob->pCallingClient->State == GPC_STATE_READY) {
//
// complete the request to the client
//
ClientRemoveCfInfoComplete
(
pBlob->pCallingClient, // first guy who made the call
pBlob, // completing blob
pBlob->LastStatus // status
);
NDIS_LOCK(&pBlob->Lock);
//
// notify any pending client about the status
//
if (pClient2 = pBlob->pCallingClient2) {
pBlob->pCallingClient2 = NULL;
NDIS_UNLOCK(&pBlob->Lock);
//
// complete the request to this client
//
ClientRemoveCfInfoComplete
(
pClient2, // the guy who made the call
pBlob, // completing blob
pBlob->LastStatus // status
);
} else {
NDIS_UNLOCK(&pBlob->Lock);
}
//pBlob->State = GPC_STATE_READY;
if (pBlob->LastStatus == GPC_STATUS_SUCCESS) {
//
// release the mapping handle
//
FreeHandle(pBlob->ClHandle);
//
// all clients have reported
// remove the blob
//
REFDEL(&pBlob->RefCount, 'BLOB');
//DereferenceBlob(&pBlob);
} else {
//
// blob not removed - restore the object type
//
pBlob->ObjectType = GPC_ENUM_CFINFO_TYPE;
//
// resume the mapping handle
//
ResumeHandle(pBlob->ClHandle);
}
}
} else { // if (pBlob->State....)
//
// we are removing the blob since we failed to add it
// to ALL clients.
//
ASSERT(pBlob->State == GPC_STATE_ADD);
//
// Release the AddFailed block so that the AddComplete
// will resume
//
CTESignal(&pBlob->WaitBlockAddFailed, pBlob->LastStatus);
}
}
//
// release the one we got earlier
//
//DereferenceClient(pClient);
TRACE(BLOB, 0, 0, "GpcRemoveCfInfoNotifyComplete==>");
}
/*
************************************************************************
GpcRemovePattern -
Called by the client to remove a pattern from the database.
Arguments
ClientHandle - client handle
GpcPatternHandle - pattern handle
Returns
GPC_STATUS
************************************************************************
*/
GPC_STATUS
GpcRemovePattern(
IN GPC_HANDLE ClientHandle,
IN GPC_HANDLE GpcPatternHandle
)
{
return(privateGpcRemovePattern(
ClientHandle,
GpcPatternHandle,
FALSE, FALSE
));
}
/*
************************************************************************
privateGpcRemovePattern -
Internal call in the GPC to indicate whether this is forceful removal.
Arguments
ClientHandle - client handle
GpcPatternHandle - pattern handle
Returns
GPC_STATUS
************************************************************************
*/
GPC_STATUS
privateGpcRemovePattern(
IN GPC_HANDLE ClientHandle,
IN GPC_HANDLE GpcPatternHandle,
IN BOOLEAN ForceRemoval ,
IN BOOLEAN DbLocked
)
{
GPC_STATUS Status = GPC_STATUS_SUCCESS;
PPATTERN_BLOCK pPattern;
PCLIENT_BLOCK pClient;
PPROTOCOL_BLOCK pProtocol;
ULONG Flags;
ULONG CfIndex;
ULONG ProtocolId;
TRACE(PATTERN, ClientHandle, GpcPatternHandle, "GpcRemovePattern");
DBGPRINT(PATTERN, ("GpcRemovePattern: Client=%X Pattern=%X\n",
ClientHandle, GpcPatternHandle));
VERIFY_OBJECT(ClientHandle, GPC_ENUM_CLIENT_TYPE);
VERIFY_OBJECT(GpcPatternHandle, GPC_ENUM_PATTERN_TYPE);
pClient = (PCLIENT_BLOCK)ClientHandle;
pPattern = (PPATTERN_BLOCK)GpcPatternHandle;
ASSERT(pClient);
ASSERT(pPattern);
CfIndex = pClient->pCfBlock->AssignedIndex;
ProtocolId = pPattern->ProtocolTemplate;
pProtocol = &glData.pProtocols[ProtocolId];
//
// If the pattern has already been removed by the ADAPTER (mostly WAN link)
// going down, just return with an error. The memory is valid since the
// ProxyRemovePattern function added a REF.
//
NDIS_LOCK(&pPattern->Lock);
if (!ForceRemoval && (pPattern->State != GPC_STATE_READY)) {
NDIS_UNLOCK(&pPattern->Lock);
return GPC_STATUS_INVALID_HANDLE;
} else {
NDIS_UNLOCK(&pPattern->Lock);
}
//
// determine weather its a specific or generic pattern
//
Flags = pPattern->Flags;
if (TEST_BIT_ON(Flags, PATTERN_SPECIFIC)) {
//
// this is a specific pattern, call the appropriate routine
// to remove from db
//
Status = RemoveSpecificPattern(
pClient,
pProtocol,
pPattern,
ForceRemoval,
DbLocked
);
} else {
//
// this is a generic pattern, call the appropriate routine
// to remove from db
//
Status = RemoveGenericPattern(
pClient,
pProtocol,
pPattern
);
}
TRACE(PATTERN, Status, 0, "GpcRemovePattern==>");
if (NT_SUCCESS(Status)) {
if (TEST_BIT_ON(Flags, PATTERN_SPECIFIC)) {
ProtocolStatInc(ProtocolId,DeletedSp);
ProtocolStatDec(ProtocolId,CurrentSp);
NdisInterlockedDecrement(&pProtocol->SpecificPatternCount);
} else {
ProtocolStatInc(ProtocolId,DeletedGp);
ProtocolStatDec(ProtocolId,CurrentGp);
NdisInterlockedDecrement(&pProtocol->GenericPatternCount);
}
}
DBGPRINT(PATTERN, ("GpcRemovePattern: Client=%X Pattern=%X, Status=%X\n",
ClientHandle, GpcPatternHandle,Status));
return Status;
}
/*
************************************************************************
GpcClassifyPattern -
Called by the client to classify a pattern and get back a client blob
context and a classification handle.
Arguments
ClientHandle - client handle
ProtocolTemplate - the protocol template to use
pPattern - pointer to pattern
pClientCfInfoContext - OUT, the client's blob context
pClassificationHandle - OUT, classification handle
Returns
GPC_STATUS: GPC_STATUS_NOT_FOUND
************************************************************************
*/
GPC_STATUS
GpcClassifyPattern(
IN GPC_HANDLE ClientHandle,
IN ULONG ProtocolTemplate,
IN PVOID pPattern,
OUT PGPC_CLIENT_HANDLE pClientCfInfoContext, // optional
IN OUT PCLASSIFICATION_HANDLE pClassificationHandle,
IN ULONG Offset,
IN PULONG pValue,
IN BOOLEAN bNoCache
)
{
GPC_STATUS Status;
PPATTERN_BLOCK pPatternBlock;
PCLIENT_BLOCK pClient;
PPROTOCOL_BLOCK pProtocol;
PGPC_IP_PATTERN pIp = (PGPC_IP_PATTERN)pPattern;
KIRQL CHirql;
PBLOB_BLOCK pBlob;
TRACE(CLASSIFY, ClientHandle, *pClassificationHandle, "GpcClassifyPattern<==");
VERIFY_OBJECT(ClientHandle, GPC_ENUM_CLIENT_TYPE);
ASSERT(ClientHandle);
ASSERT(pPattern);
//ASSERT(pClientCfInfoContext);
ASSERT(pClassificationHandle);
Status = GPC_STATUS_SUCCESS;
if (ProtocolTemplate >= GPC_PROTOCOL_TEMPLATE_MAX) {
return GPC_STATUS_INVALID_PARAMETER;
}
pProtocol = &glData.pProtocols[ProtocolTemplate];
//
// Optimization - check if there are any patterns installed
//
if (pProtocol->SpecificPatternCount == 0
&&
pProtocol->GenericPatternCount == 0 ) {
if (pClientCfInfoContext) {
*pClientCfInfoContext = NULL;
}
*pClassificationHandle = (CLASSIFICATION_HANDLE)0;
DBGPRINT(CLASSIFY, ("GpcClassifyPattern: Client=%X no patterns returned %X\n",
ClientHandle, GPC_STATUS_NOT_FOUND));
TRACE(CLASSIFY, ClientHandle, GPC_STATUS_NOT_FOUND, "GpcClassifyPattern (1)" );
return GPC_STATUS_NOT_FOUND;
}
pClient = (PCLIENT_BLOCK)ClientHandle;
if (ProtocolTemplate == GPC_PROTOCOL_TEMPLATE_IP) {
pIp = (PGPC_IP_PATTERN)pPattern;
pIp->Reserved[0] = pIp->Reserved[1] = pIp->Reserved[2] = 0;
DBGPRINT(CLASSIFY, ("GpcClassifyPattern: Client=%X, CH=%d\n",
ClientHandle, *pClassificationHandle));
DBGPRINT(CLASSIFY, ("IP: ifc={%d,%d} src=%08X:%04x, dst=%08X:%04x, prot=%d rsv=%x,%x,%x\n",
pIp->InterfaceId.InterfaceId,
pIp->InterfaceId.LinkId,
pIp->SrcAddr,
pIp->gpcSrcPort,
pIp->DstAddr,
pIp->gpcDstPort,
pIp->ProtocolId,
pIp->Reserved[0],
pIp->Reserved[1],
pIp->Reserved[2]
));
}
ProtocolStatInc(ProtocolTemplate, ClassificationRequests);
//
// verify the classification handle, if it's valid, simply return
//
if (*pClassificationHandle && (pClientCfInfoContext || pValue)) {
Status = GetClientCtxAndUlongFromCfInfo(ClientHandle,
pClassificationHandle,
pClientCfInfoContext,
Offset,
pValue
);
ProtocolStatInc(ProtocolTemplate, PatternsClassified);
DBGPRINT(CLASSIFY, ("GpcClassifyPattern: Client=%X returned immediate CH %d\n",
pClient, *pClassificationHandle));
TRACE(CLASSIFY, pClient, *pClassificationHandle, "GpcClassifyPattern (2)" );
return Status;
}
//
// there pattern needs to be classified
// this should find the classification handle
//
Status = InternalSearchPattern(
pClient,
pProtocol,
pPattern,
&pPatternBlock,
pClassificationHandle,
bNoCache
);
if (*pClassificationHandle && (pClientCfInfoContext || pValue)) {
Status = GetClientCtxAndUlongFromCfInfo(ClientHandle,
pClassificationHandle,
pClientCfInfoContext,
Offset,
pValue
);
} else if ((!NT_SUCCESS(Status)) &&
pPatternBlock &&
pClientCfInfoContext) {
// it is likely that we could not allocate the Auto Specific pattern
// just try to send the context anyway.
READ_LOCK(&glData.ChLock, &CHirql);
pBlob = GetBlobFromPattern(pPatternBlock, GetCFIndexFromClient(ClientHandle));
if(pBlob) {
*pClientCfInfoContext = pBlob->arClientCtx[GetClientIndexFromClient(ClientHandle)];
} else {
Status = GPC_STATUS_NOT_FOUND;
}
READ_UNLOCK(&glData.ChLock, CHirql);
} else if (!*pClassificationHandle) {
//
// none found,
//
if (pClientCfInfoContext) {
*pClientCfInfoContext = NULL;
}
Status = GPC_STATUS_NOT_FOUND;
} else {
Status = GPC_STATUS_SUCCESS;
}
if (pPatternBlock) {
//DereferencePattern(pPatternBlock, pClient->pCfBlock);
ProtocolStatInc(ProtocolTemplate, PatternsClassified);
}
TRACE(CLASSIFY, pPatternBlock, Status, "GpcClassifyPattern==>");
DBGPRINT(CLASSIFY, ("GpcClassifyPattern: Client=%X returned Pattern=%X, CH=%d, Status=%X\n",
pClient, pPattern, *pClassificationHandle, Status));
return Status;
}
/*
************************************************************************
GpcClassifyPacket -
Called by the client to classify a packet and get back a client blob
context and a classification handle.
Content is extracted from the packet and placed into a protocol specific
structure (IP).
For IP, if fragmentation is ON for the client:
o First fragment will create a hash table entry
o Other fragments will be looked in the hash by the packet ID
o Last fragment will cause entry to be deleted.
Arguments
ClientHandle - client handle
ProtocolTemplate - the protocol template
pNdisPacket - ndis packet
TransportHeaderOffset - byte offset of the start of the transport
header from the beginning of the packet
pClientCfInfoContext - OUT, client blob context
pClassificationHandle - OUT, classification handle
Returns
GPC_STATUS
************************************************************************
*/
GPC_STATUS
GpcClassifyPacket(
IN GPC_HANDLE ClientHandle,
IN ULONG ProtocolTemplate,
IN PVOID pPacket,
IN ULONG TransportHeaderOffset,
IN PTC_INTERFACE_ID pInterfaceId,
OUT PGPC_CLIENT_HANDLE pClientCfInfoContext, //optional
OUT PCLASSIFICATION_HANDLE pClassificationHandle
)
{
GPC_STATUS Status = GPC_STATUS_SUCCESS;
PNDIS_PACKET pNdisPacket = NULL;
PCLIENT_BLOCK pClient;
PCF_BLOCK pCf;
PPATTERN_BLOCK pPattern = NULL;
PPROTOCOL_BLOCK pProtocol;
PBLOB_BLOCK pBlob = NULL;
ULONG CfIndex;
int i;
GPC_IP_PATTERN IpPattern;
GPC_IPX_PATTERN IpxPattern;
PVOID pKey = NULL;
PVOID pAddr;
UINT Len, Tot;
PNDIS_BUFFER pNdisBuf1, pNdisBuf2;
PIP_HEADER pIpHdr;
PIPX_HEADER pIpxHdr;
USHORT PacketId;
USHORT FragOffset;
UINT IpHdrLen;
PUDP_HEADER pUDPHdr;
UCHAR PktProtocol;
BOOLEAN bFragment = FALSE;
BOOLEAN bLastFragment = FALSE;
BOOLEAN bFirstFragment = FALSE;
TRACE(CLASSIFY, ClientHandle, pNdisPacket, "GpcClassifyPacket");
DBGPRINT(CLASSIFY, ("GpcClassifyPacket: Client=%X CH=%d\n",
ClientHandle, *pClassificationHandle));
VERIFY_OBJECT(ClientHandle, GPC_ENUM_CLIENT_TYPE);
ASSERT(pPacket);
ASSERT(ClientHandle);
//ASSERT(pClientCfInfoContext);
ASSERT(pClassificationHandle);
if (ProtocolTemplate >= GPC_PROTOCOL_TEMPLATE_MAX) {
return GPC_STATUS_INVALID_PARAMETER;
}
pProtocol = &glData.pProtocols[ProtocolTemplate];
//
// Optimization - check if there are any patterns installed
//
if (pProtocol->SpecificPatternCount == 0
&&
pProtocol->GenericPatternCount == 0 ) {
if (pClientCfInfoContext) {
*pClientCfInfoContext = NULL;
}
*pClassificationHandle = 0;
DBGPRINT(CLASSIFY, ("GpcClassifyPacket: Client=%X no patterns returned %X\n",
ClientHandle, GPC_STATUS_NOT_FOUND));
return GPC_STATUS_NOT_FOUND;
}
pClient = (PCLIENT_BLOCK)ClientHandle;
pNdisPacket = (PNDIS_PACKET)pPacket;
//
// get the classification handle from the packet
// if there - extract the blob pointer and the client blob context
// directly and return
//
//
// o/w, we need to look inside the packet
// Parse the packet into a pattern and make a db search
// first match a specific pattern, and then search the generic
// database(s) for the given CF
//
pCf = pClient->pCfBlock;
CfIndex = pCf->AssignedIndex;
ProtocolStatInc(ProtocolTemplate,ClassificationRequests);
*pClassificationHandle = 0;
//
// get the pattern from the packet
//
//
// get the first NDIS buffer - assuming it is a MAC header
//
NdisGetFirstBufferFromPacket(pNdisPacket,
&pNdisBuf1, // Ndis buffer 1 desc.
&pAddr, // buffer VA
&Len, // buffer length
&Tot // total length (all buffs)
);
ASSERT(Tot > TransportHeaderOffset);
while (Len <= TransportHeaderOffset) {
//
// Transport header is not in this buffer,
// try the next buffer
//
TransportHeaderOffset -= Len;
NdisGetNextBuffer(pNdisBuf1, &pNdisBuf2);
ASSERT(pNdisBuf2); // should never happen!!
NdisQueryBuffer(pNdisBuf2, &pAddr, &Len);
pNdisBuf1 = pNdisBuf2;
}
switch (ProtocolTemplate) {
case GPC_PROTOCOL_TEMPLATE_IP:
//
// fill the pattern with '0'
//
RtlZeroMemory(&IpPattern, sizeof(IpPattern));
//
// parse IP packet here...
//
pIpHdr = (PIP_HEADER)(((PUCHAR)pAddr) + TransportHeaderOffset);
IpHdrLen = (pIpHdr->iph_verlen & (uchar)~IP_VER_FLAG) << 2;
FragOffset = pIpHdr->iph_offset & IP_OFFSET_MASK;
FragOffset = net_short(FragOffset) * 8;
PacketId = pIpHdr->iph_id;
//
// check for fragmentation
//
bFragment = (pIpHdr->iph_offset & IP_MF_FLAG) || (FragOffset > 0);
bFirstFragment = bFragment && (FragOffset == 0);
bLastFragment = bFragment &&
TEST_BIT_OFF(pIpHdr->iph_offset, IP_MF_FLAG);
//
// sanity check - doesn't make sense to have a single fragment
//
ASSERT(!bFirstFragment || !bLastFragment);
if (TEST_BIT_ON(pClient->Flags, GPC_FLAGS_FRAGMENT) &&
(bFragment && ! bFirstFragment)) {
//
// client is interested in fragmentation and this is a
// a fragment, but not the first one.
// It will be handled later when we find the pattern
//
Status = HandleFragment(
pClient,
pProtocol,
bFirstFragment, // first frag
bLastFragment, // last frag
PacketId,
&pPattern,
&pBlob
);
} else {
//
// not a fragment, or is the first one - we have to search db
//
IpPattern.SrcAddr = pIpHdr->iph_src;
IpPattern.DstAddr = pIpHdr->iph_dest;
IpPattern.ProtocolId = pIpHdr->iph_protocol;
//
// case the ProtocolId and fill the appropriate union
//
switch (IpPattern.ProtocolId) {
case IPPROTO_IP:
//
// we have everything so far
//
break;
case IPPROTO_TCP:
case IPPROTO_UDP:
//
// need to get those port numbers
//
if (IpHdrLen < Len) {
//
// the UDP/TCP header is in the same buffer
//
pUDPHdr = (PUDP_HEADER)((PUCHAR)pIpHdr + IpHdrLen);
} else {
//
// get the next buffer
//
NdisGetNextBuffer(pNdisBuf1, &pNdisBuf2);
ASSERT(pNdisBuf2);
if (IpHdrLen > Len) {
//
// There is an optional header buffer, so get the next
// buffer to reach the udp/tcp header
//
pNdisBuf1 = pNdisBuf2;
NdisGetNextBuffer(pNdisBuf1, &pNdisBuf2);
ASSERT(pNdisBuf2);
}
NdisQueryBuffer(pNdisBuf2, &pUDPHdr, &Len);
}
IpPattern.gpcSrcPort = pUDPHdr->uh_src;
IpPattern.gpcDstPort = pUDPHdr->uh_dest;
#if INTERFACE_ID
IpPattern.InterfaceId.InterfaceId = pInterfaceId->InterfaceId;
IpPattern.InterfaceId.LinkId = pInterfaceId->LinkId;
#endif
break;
case IPPROTO_ICMP:
case IPPROTO_IGMP:
default:
//
// The default will cover all IP_PROTO_RAW packets. Note that in this case, all we care about
// is the InterfaceID
//
#if INTERFACE_ID
IpPattern.InterfaceId.InterfaceId = pInterfaceId->InterfaceId;
IpPattern.InterfaceId.LinkId = pInterfaceId->LinkId;
#endif
break;
case IPPROTO_IPSEC:
pKey = NULL;
Status = GPC_STATUS_NOT_SUPPORTED;
}
pKey = &IpPattern;
break;
}
DBGPRINT(CLASSIFY, ("IP: ifc={%d,%d} src=%X:%x, dst=%X:%x, prot=%x, rsv=%x,%x,%x \n",
IpPattern.InterfaceId.InterfaceId,
IpPattern.InterfaceId.LinkId,
IpPattern.SrcAddr,
IpPattern.gpcSrcPort,
IpPattern.DstAddr,
IpPattern.gpcDstPort,
IpPattern.ProtocolId,
IpPattern.Reserved[0],
IpPattern.Reserved[1],
IpPattern.Reserved[2]
));
break;
case GPC_PROTOCOL_TEMPLATE_IPX:
//
// fill the pattern with '0'
//
RtlZeroMemory(&IpxPattern, sizeof(IpxPattern));
//
// parse IPX packet here...
//
pIpxHdr = (PIPX_HEADER)(((PUCHAR)pAddr) + TransportHeaderOffset);
//
// source
//
IpxPattern.Src.NetworkAddress = *(ULONG *)pIpxHdr->SourceNetwork;
RtlMoveMemory(IpxPattern.Src.NodeAddress, pIpxHdr->SourceNode,6);
IpxPattern.Src.Socket = pIpxHdr->SourceSocket;
//
// destination
//
IpxPattern.Dest.NetworkAddress = *(ULONG *)pIpxHdr->DestinationNetwork;
RtlMoveMemory(IpxPattern.Dest.NodeAddress, pIpxHdr->DestinationNode,6);
IpxPattern.Dest.Socket = pIpxHdr->DestinationSocket;
pKey = &IpxPattern;
break;
default:
Status = GPC_STATUS_INVALID_PARAMETER;
}
if (NT_SUCCESS(Status) && pPattern == NULL) {
//
// no failure so far but no pattern found either
// search for the pattern
//
ASSERT(pKey);
//
// if there is a match, the pattern ref count will be bumped
// up and we need to release it when we're done.
//
Status = InternalSearchPattern(
pClient,
pProtocol,
pKey,
&pPattern,
pClassificationHandle,
FALSE
);
}
if (*pClassificationHandle) {
if (pClientCfInfoContext) {
Status = GpcGetCfInfoClientContext(ClientHandle,
*pClassificationHandle,
pClientCfInfoContext);
}
ProtocolStatInc(ProtocolTemplate, PacketsClassified);
} else {
//ASSERT(pBlob == NULL);
//
// none found, or some other error occured.
//
if (pClientCfInfoContext) {
*pClientCfInfoContext = NULL;
}
*pClassificationHandle = 0;
Status = GPC_STATUS_NOT_FOUND;
}
TRACE(CLASSIFY, pPattern, Status, "GpcClassifyPacket==>");
DBGPRINT(CLASSIFY, ("GpcClassifyPacket: Client=%X returned Pattern=%X, CH=%d, Status=%X\n",
pClient, pPattern, *pClassificationHandle, Status));
return Status;
}
/*
************************************************************************
GpcEnumCfInfo -
Called to enumerate CfInfo's (and attached filters).
For each CfInfo, GPC will return the CfInfo blob and the list of
pattern attached to it.
Arguments
ClientHandle - the calling client
pBlob - the next cfinfo to enumerate, NULL for the first
pBlobCount - in: requested; out: returned
pBufferSize - in: allocated; out: bytes returned
Buffer - output buffer
Returns
GPC_STATUS
************************************************************************
*/
GPC_STATUS
GpcEnumCfInfo(
IN GPC_HANDLE ClientHandle,
IN OUT PHANDLE pCfInfoHandle,
OUT PHANDLE pCfInfoMapHandle,
IN OUT PULONG pCfInfoCount,
IN OUT PULONG pBufferSize,
IN PGPC_ENUM_CFINFO_BUFFER Buffer
)
{
GPC_STATUS Status = GPC_STATUS_SUCCESS;
GPC_STATUS st;
PBLOB_BLOCK pBlob = NULL;
PCF_BLOCK pCf;
PLIST_ENTRY pEntry, pHead;
PPATTERN_BLOCK pPattern;
ULONG cCfInfo = 0;
ULONG cTotalBytes = 0;
ULONG cPatterns, cValidPatterns;
ULONG size, cValidSize;
ULONG PatternMaskLen;
ULONG PatternSize;
ULONG i;
PCHAR p, q;
PGENERIC_PATTERN_DB pGenDb;
UNICODE_STRING CfInfoName;
PGPC_GEN_PATTERN pGenPattern;
BOOLEAN bEnum;
KIRQL ReadIrql;
KIRQL irql;
PCLIENT_BLOCK pNotifiedClient;
GPC_CLIENT_HANDLE NotifiedClientCtx;
BOOLEAN found = FALSE;
UNICODE_STRING UniStr;
//
// debug checks
//
ASSERT(ClientHandle);
ASSERT(pCfInfoHandle);
ASSERT(pCfInfoMapHandle);
ASSERT(pCfInfoCount);
ASSERT(pBufferSize);
ASSERT(Buffer);
cValidPatterns = 0;
VERIFY_OBJECT(ClientHandle, GPC_ENUM_CLIENT_TYPE);
pCf = ((PCLIENT_BLOCK)ClientHandle)->pCfBlock;
//NDIS_LOCK(&pCf->Lock);
RSC_WRITE_LOCK(&pCf->ClientSync, &irql);
//
// check if we start from a previous blob
//
if (*pCfInfoHandle) {
pBlob = (PBLOB_BLOCK)*pCfInfoHandle;
NDIS_LOCK(&pBlob->Lock);
if (pBlob->State == GPC_STATE_REMOVE) {
//
// the blob has been marked for removal
//
NDIS_UNLOCK(&pBlob->Lock);
//NDIS_UNLOCK(&pCf->Lock);
RSC_WRITE_UNLOCK(&pCf->ClientSync, irql);
*pCfInfoMapHandle = NULL;
return STATUS_DATA_ERROR;
}
//NDIS_UNLOCK(&pBlob->Lock);
} else {
//
// find the first (good) blob to enumerate.
//
//
// Need to take pCf->Lock to manipulate or
// traverse the Blobs on it
//
NDIS_LOCK(&pCf->Lock);
if (IsListEmpty(&pCf->BlobList)) {
//
// no blobs to enumerate
//
*pCfInfoCount = 0;
*pBufferSize = 0;
*pCfInfoMapHandle = NULL;
//NDIS_UNLOCK(&pCf->Lock);
NDIS_UNLOCK(&pCf->Lock);
RSC_WRITE_UNLOCK(&pCf->ClientSync, irql);
return GPC_STATUS_SUCCESS;
} else {
//
// Find a good Blob (something that's not getting deleted)
//
pEntry = pCf->BlobList.Flink;
while (&pCf->BlobList != pEntry) {
pBlob = CONTAINING_RECORD(pEntry, BLOB_BLOCK, CfLinkage);
NDIS_LOCK(&pBlob->Lock);
if ((pBlob->State == GPC_STATE_READY) &&
(pBlob->ObjectType != GPC_ENUM_INVALID)) {
found = TRUE;
break;
} else {
//Aha! The first Blob is bad!!
pEntry = pEntry->Flink;
NDIS_UNLOCK(&pBlob->Lock);
}
}
//
// Couldn't find anything to enumerate.
if (!found) {
//No Blobs to enumerate
*pCfInfoCount = 0;
*pBufferSize = 0;
*pCfInfoMapHandle = NULL;
NDIS_UNLOCK(&pCf->Lock);
//NDIS_UNLOCK(&pCf->Lock);
RSC_WRITE_UNLOCK(&pCf->ClientSync, irql);
return GPC_STATUS_SUCCESS;
}
}
NDIS_UNLOCK(&pCf->Lock);
}
ASSERT(pBlob);
*pCfInfoMapHandle = pBlob->ClHandle;
//
// at this point, we should have a blob pointer that we can
// start enumerating. The CF is still lock, so we can safely
// walk the BlobList
// The blob lock is also taken so we can scan the pattern list
//
for ( ; ; ) { // we'll break out from this
//NDIS_LOCK(&pBlob->Lock);
//NdisInterlockedIncrement(&pBlob->RefCount);
//ASSERT (pBlob->State != GPC_STATE_REMOVE);
//NDIS_UNLOCK(&pBlob->Lock);
pHead = &pBlob->PatternList;
pEntry = pHead->Flink;
//
// Calculate how much space is needed for just one CfInfo
// and all of its filters
//
size = sizeof(GPC_ENUM_CFINFO_BUFFER) + pBlob->ClientDataSize;
//
// patterns might become invalid while we try to enum the CF, so we set cValidSize here
// we have to align cValidSize so that the next CfInfo starts at a word boundary.
//
size = ((size + (sizeof(PVOID)-1)) & ~(sizeof(PVOID)-1));
cValidSize = size;
//
// Count the patterns
//
for (cPatterns = 0, PatternMaskLen = 0;
pHead != pEntry;
cPatterns++, pEntry = pEntry->Flink) {
pPattern = CONTAINING_RECORD(pEntry,
PATTERN_BLOCK,
BlobLinkage[pCf->AssignedIndex]);
PatternMaskLen += (sizeof(GPC_GEN_PATTERN) +
2 * glData.pProtocols[pPattern->ProtocolTemplate].PatternSize);
}
//
// check if we have enough buffer space
//
size += PatternMaskLen;
cValidPatterns = 0;
if ((cTotalBytes + size) <= *pBufferSize) {
//
// yes, we can squeeze one more...
//
pEntry = pHead->Flink;
pGenPattern = &Buffer->GenericPattern[0];
for (i = 0;
((i < cPatterns) && (pEntry != pHead));
i++, pEntry = pEntry->Flink) {
//
// fill all the patterns + masks in
//
pPattern = CONTAINING_RECORD(pEntry,
PATTERN_BLOCK,
BlobLinkage[pCf->AssignedIndex] );
NDIS_LOCK(&pPattern->Lock);
// Check for pattern's state...
//
if (GPC_STATE_READY != pPattern->State) {
// don't try to list it out if its being removed!
NDIS_UNLOCK(&pPattern->Lock);
continue;
}
cValidSize += (sizeof(GPC_GEN_PATTERN) +
2 * glData.pProtocols[pPattern->ProtocolTemplate].PatternSize);
PatternSize = glData.pProtocols[pPattern->ProtocolTemplate].PatternSize;
pGenPattern->ProtocolId = pPattern->ProtocolTemplate;
pGenPattern->PatternSize = PatternSize;
pGenPattern->PatternOffset = sizeof(GPC_GEN_PATTERN);
pGenPattern->MaskOffset = pGenPattern->PatternOffset + PatternSize;
p = ((PUCHAR)pGenPattern) + pGenPattern->PatternOffset;
cValidPatterns++;
//
// get the pattern and mask bits
//
if (TEST_BIT_ON(pPattern->Flags, PATTERN_SPECIFIC)) {
//
// this is a specific pattern
//
READ_LOCK(&glData.pProtocols[pPattern->ProtocolTemplate].SpecificDb.Lock, &ReadIrql);
ASSERT(pPattern->DbCtx);
q = GetKeyPtrFromSpecificPatternHandle
(((SpecificPatternHandle)pPattern->DbCtx));
RtlMoveMemory(p, q, PatternSize);
p += PatternSize;
//
// that's a specific pattern, remember?
//
NdisFillMemory(p, PatternSize, (CHAR)0xff);
READ_UNLOCK(&glData.pProtocols[pPattern->ProtocolTemplate].SpecificDb.Lock, ReadIrql);
} else {
pGenDb = &pCf->arpGenericDb[pPattern->ProtocolTemplate][pPattern->Priority];
READ_LOCK(&pGenDb->Lock, &ReadIrql);
//
// generic pattern
//
ASSERT(pPattern->DbCtx);
q = GetKeyPtrFromPatternHandle(pGenDb->pRhizome,
pPattern->DbCtx);
RtlMoveMemory(p, q, PatternSize);
p += PatternSize;
//
// mask
//
q = GetMaskPtrFromPatternHandle(pGenDb->pRhizome,
pPattern->DbCtx);
RtlMoveMemory(p, q, PatternSize);
READ_UNLOCK(&pGenDb->Lock, ReadIrql);
}
p += PatternSize;
pGenPattern = (PGPC_GEN_PATTERN)p;
NDIS_UNLOCK(&pPattern->Lock);
} // for (i = 0; ...)
//
// we can now fill the CfInfo data.
// 'pGenPattern' now points to the place where we can safely
// store the CfInfo structure, and update the pointer
//
Buffer->InstanceNameLength = 0;
pNotifiedClient = pBlob->pNotifiedClient;
NotifiedClientCtx = pBlob->NotifiedClientCtx;
st = GPC_STATUS_FAILURE;
if (pNotifiedClient) {
if (pNotifiedClient->FuncList.ClGetCfInfoName &&
NotifiedClientCtx) {
st = pNotifiedClient->FuncList.ClGetCfInfoName(
pNotifiedClient->ClientCtx,
NotifiedClientCtx,
&CfInfoName
);
if (CfInfoName.Length >= MAX_STRING_LENGTH * sizeof(WCHAR))
CfInfoName.Length = (MAX_STRING_LENGTH-1) * sizeof(WCHAR);
//
// RajeshSu claims this can never happen.
//
ASSERT(NT_SUCCESS(st));
}
}
if (NT_SUCCESS(st)) {
//
// copy the instance name
//
Buffer->InstanceNameLength = CfInfoName.Length;
RtlMoveMemory(Buffer->InstanceName,
CfInfoName.Buffer,
CfInfoName.Length
);
} else {
//
// generate a default name
//
if (NotifiedClientCtx) {
RtlInitUnicodeString(&UniStr, L"Flow <ClientNotified>");
} else {
RtlInitUnicodeString(&UniStr, L"Flow <unknown name>");
}
RtlCopyMemory(Buffer->InstanceName, UniStr.Buffer, UniStr.Length);
Buffer->InstanceNameLength = UniStr.Length;
}
Buffer->InstanceName[Buffer->InstanceNameLength/sizeof(WCHAR)] = L'\0';
//
// 'pGenPattern' should point to the location right after the last
// mask, so we fill the CfInfo data there
//
//NDIS_LOCK(&pBlob->Lock);
RtlMoveMemory(pGenPattern,
pBlob->pClientData,
pBlob->ClientDataSize);
Buffer->Length = cValidSize;
Buffer->CfInfoSize = pBlob->ClientDataSize;
Buffer->CfInfoOffset = (ULONG)((PCHAR)pGenPattern
- (PCHAR)Buffer); // offset to structure
Buffer->PatternCount = cValidPatterns;
Buffer->PatternMaskLen = PatternMaskLen;
Buffer->OwnerClientCtx = pBlob->pOwnerClient->ClientCtx;
//
// release the blob lock we've got earlier
//
NDIS_UNLOCK(&pBlob->Lock);
//
// update total counts
//
cCfInfo++;
cTotalBytes += cValidSize;
Buffer = (PGPC_ENUM_CFINFO_BUFFER)((PCHAR)Buffer + cValidSize);
pEntry = pBlob->CfLinkage.Flink;
//
// advance to the next blob in the list
//
if (pEntry == &pCf->BlobList) {
//
// end of blob list, reset the blob to NULL and return
//
pBlob = NULL;
*pCfInfoMapHandle = NULL;
break;
}
pBlob = CONTAINING_RECORD(pEntry,
BLOB_BLOCK,
CfLinkage);
*pCfInfoMapHandle = pBlob->ClHandle;
if (cCfInfo == *pCfInfoCount) {
//
// enough CfInfo's filled
//
break;
}
//
// lock the blob for the next cycle
//
NDIS_LOCK(&pBlob->Lock);
} else { // if (cTotalBytes + size <= *pBufferSize)...
//
// size is too small, set return values and break
//
//DereferenceBlob(&pBlob);
if (cCfInfo == 0) {
Status = GPC_STATUS_INSUFFICIENT_BUFFER;
}
//
// release the blob lock we've got earlier
//
NDIS_UNLOCK(&pBlob->Lock);
break;
}
} // for (;;")
//NDIS_UNLOCK(&pCf->Lock);
RSC_WRITE_UNLOCK(&pCf->ClientSync, irql);
*pCfInfoHandle = (GPC_HANDLE)pBlob;
*pCfInfoCount = cCfInfo;
*pBufferSize = cTotalBytes;
return Status;
}