|
|
/*
************************************************************************
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';
// 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)) { UninitSpecificPatternDb(&glData.pProtocols[i].SpecificDb); TRACE(INIT, Status, 0, "InitGpc==>"); break; } } // for (i...)
if (!NT_SUCCESS (Status)) { while (i-- != 0) { UninitSpecificPatternDb (&glData.pProtocols[i].SpecificDb); UninitFragmentDb((PFRAGMENT_DB)glData.pProtocols[i].pProtocolDb); } return Status; } //
// init handle mapping table
//
Status = InitMapHandles();
if (!NT_SUCCESS(Status)) { TRACE(INIT, Status, 0, "InitGpc==>");
for (i = 0; i < GPC_PROTOCOL_TEMPLATE_MAX; i++) { UninitSpecificPatternDb (&glData.pProtocols[i].SpecificDb); UninitFragmentDb((PFRAGMENT_DB)glData.pProtocols[i].pProtocolDb); } return Status; }
//
// init classification index table
//
Status = InitClassificationHandleTbl(&glData.pCHTable);
if (!NT_SUCCESS(Status)) { TRACE(INIT, Status, 0, "InitGpc==>");
UninitMapHandles(); for (i = 0; i < GPC_PROTOCOL_TEMPLATE_MAX; i++) { UninitSpecificPatternDb (&glData.pProtocols[i].SpecificDb); UninitFragmentDb((PFRAGMENT_DB)glData.pProtocols[i].pProtocolDb); } return Status; }
#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);
TRACE(INIT, Status, 0, "InitGpc==>");
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 ) { 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;
TRACE(BLOB, ClientHandle, ClientCfInfoContext, "GpcAddCfInfo");
VERIFY_OBJECT(ClientHandle, GPC_ENUM_CLIENT_TYPE);
*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);
if (pBlob) {
#if NO_USER_PENDING
//
// this will be only required until we implement the user level
// pending report
//
CTEInitBlockStruc(&pBlob->WaitBlock);
#endif
//
// 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?!?
//
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) {
//
// 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
//
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);
InterlockedDecrement(&pProtocol->AutoSpecificPatternCount);
} else {
NDIS_DPR_UNLOCK(&pPattern->Lock); NDIS_UNLOCK(&pBlob->Lock);
} privateGpcRemovePattern(ClientHandle, (GPC_HANDLE)pPattern, TRUE); 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 ));
}
/*
************************************************************************
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 ) {
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 ); } 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; }
|