Source code of Windows XP (NT5)
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.
 
 
 
 
 
 

1996 lines
44 KiB

/*
************************************************************************
Copyright (c) 1996-1997 Microsoft Corporation
Module Name:
gpcdb.c
Abstract:
This file contains specific patterns database routines
Author:
Ofer Bar -April 15, 1997
Environment:
Kernel mode
Revision History:
************************************************************************
*/
#include "gpcpre.h"
//
// locals
//
/*
************************************************************************
CreateNewCfBlock -
create and return a new CF block for internal use
Arguments
CfId -
MaxPriorities -
Returns
pointer to the new CF block or NULL for no memory resources
************************************************************************
*/
PCF_BLOCK
CreateNewCfBlock(
IN ULONG CfId,
IN ULONG MaxPriorities
)
{
PCF_BLOCK pCf;
int i;
GPC_STATUS Status;
GpcAllocFromLL(&pCf, &ClassificationFamilyLL, ClassificationFamilyTag);
if (pCf) {
//
// reset all
//
NdisZeroMemory(pCf, sizeof(CF_BLOCK));
InitializeListHead(&pCf->ClientList);
InitializeListHead(&pCf->BlobList);
NDIS_INIT_LOCK(&pCf->Lock);
//pCf->ClientSync = 0;
//INIT_LOCK(&pCf->ClientSync);
NDIS_INIT_LOCK(&pCf->ClientSync);
pCf->NumberOfClients = 0;
pCf->AssignedIndex = CfId;
pCf->MaxPriorities = MaxPriorities;
ReferenceInit(&pCf->RefCount, pCf, ReleaseCfBlock);
REFADD(&pCf->RefCount, 'CFBK');
//
// for each protocol, reset the generic pattern
// this will be dynamically allocated later
// when pattern are installed
//
for (i = 0; i < GPC_PROTOCOL_TEMPLATE_MAX; i++) {
Status = InitializeGenericDb(&pCf->arpGenericDb[i],
MaxPriorities,
glData.pProtocols[i].PatternSize);
if (Status != GPC_STATUS_SUCCESS) {
REFDEL(&pCf->RefCount, 'CFBK');
pCf = NULL;
break;
}
}
}
return pCf;
}
/*
************************************************************************
ReleaseCfBlock -
Release the CF block
Arguments
pCf - the CF block to release
Returns
void
************************************************************************
*/
VOID
ReleaseCfBlock(
IN PCF_BLOCK pCf
)
{
int i;
ASSERT(pCf);
ASSERT(IsListEmpty(&pCf->ClientList));
ASSERT(IsListEmpty(&pCf->BlobList));
ASSERT(pCf->NumberOfClients == 0);
for (i = 0; i < GPC_PROTOCOL_TEMPLATE_MAX; i++) {
if (pCf->arpGenericDb[i]) {
UninitializeGenericDb(&pCf->arpGenericDb[i],
pCf->MaxPriorities
);
}
}
NdisFreeSpinLock(&pCf->Lock);
//
// just free the memory
//
GpcFreeToLL(pCf, &ClassificationFamilyLL, ClassificationFamilyTag);
}
/*
************************************************************************
CreateNewClientBlock -
create and return a new client block for internal use
Arguments
none
Returns
pointer to the new client block or NULL for no memory resources
************************************************************************
*/
PCLIENT_BLOCK
CreateNewClientBlock(VOID)
{
PCLIENT_BLOCK pClient;
GpcAllocFromLL(&pClient, &ClientLL, ClientTag);
if (pClient) {
//
// reset all
//
NdisZeroMemory(pClient, sizeof(CLIENT_BLOCK));
pClient->ObjectType = GPC_ENUM_CLIENT_TYPE;
pClient->ClHandle = NULL;
NDIS_INIT_LOCK(&pClient->Lock);
InitializeListHead(&pClient->BlobList);
ReferenceInit(&pClient->RefCount, pClient, DereferenceClient);
REFADD(&pClient->RefCount, 'CLNT');
}
return pClient;
}
/*
************************************************************************
CreateNewPatternBlock -
create and return a new pattern block for internal use
Arguments
none
Returns
pointer to the new pattern block or NULL for no memory resources
************************************************************************
*/
PPATTERN_BLOCK
CreateNewPatternBlock(
IN ULONG Flags
)
{
PPATTERN_BLOCK pPattern;
int i;
GpcAllocFromLL(&pPattern, &PatternLL, PatternTag);
if (pPattern) {
//
// reset all
//
TRACE(PATTERN, pPattern, sizeof(PATTERN_BLOCK), "CreateNewPatternBlock");
NdisZeroMemory(pPattern, sizeof(PATTERN_BLOCK));
pPattern->ObjectType = GPC_ENUM_PATTERN_TYPE;
for (i = 0; i < GPC_CF_MAX; i++) {
InitializeListHead(&pPattern->BlobLinkage[i]);
}
InitializeListHead(&pPattern->TimerLinkage);
NDIS_INIT_LOCK(&pPattern->Lock);
pPattern->Flags = Flags;
ReferenceInit(&pPattern->RefCount, pPattern, DereferencePattern);
REFADD(&pPattern->RefCount, 'FILT');
pPattern->ClientRefCount = 1;
pPattern->State = GPC_STATE_INIT;
//AllocateHandle(&pPattern->ClHandle, (PVOID)pPattern);
}
return pPattern;
}
/*
************************************************************************
CreateNewBlobBlock -
create and return a new blob block for internal use.
A copy of ClientData is being place pointed by the new blob
Arguments
none
Returns
pointer to the new blob block or NULL for no memory resources
************************************************************************
*/
PBLOB_BLOCK
CreateNewBlobBlock(
IN ULONG ClientDataSize,
IN PVOID pClientData
)
{
PBLOB_BLOCK pBlob;
GpcAllocFromLL(&pBlob, &CfInfoLL, CfInfoTag);
if (pBlob) {
//
// reset all
//
NdisZeroMemory(pBlob, sizeof(BLOB_BLOCK));
GpcAllocMem(&pBlob->pClientData, ClientDataSize, CfInfoDataTag);
if (pBlob->pClientData) {
pBlob->ObjectType = GPC_ENUM_CFINFO_TYPE;
pBlob->ClHandle = NULL;
InitializeListHead(&pBlob->ClientLinkage);
InitializeListHead(&pBlob->PatternList);
InitializeListHead(&pBlob->CfLinkage);
pBlob->State = GPC_STATE_INIT;
pBlob->Flags = 0;
ReferenceInit(&pBlob->RefCount, pBlob, DereferenceBlob);
REFADD(&pBlob->RefCount, 'BLOB');
pBlob->ClientDataSize = ClientDataSize;
pBlob->LastStatus = GPC_STATUS_SUCCESS;
NdisMoveMemory(pBlob->pClientData, pClientData, ClientDataSize);
NDIS_INIT_LOCK(&pBlob->Lock);
//
// that's for the notified client about the CfInfo Add
//
pBlob->pNotifiedClient = NULL;
pBlob->NotifiedClientCtx = NULL;
} else {
GpcFreeToLL(pBlob, &CfInfoLL, CfInfoTag);
pBlob = NULL;
}
}
return pBlob;
}
/*
************************************************************************
AssignNewClientIndex -
Finds and returns a new index for a client on the CF. It also sets
the index as busy in the CF block.
Arguments
pClient - poinetr to the client block
Returns
a client index or (-1) for none
************************************************************************
*/
ULONG
AssignNewClientIndex(
IN PCF_BLOCK pCfBlock
)
{
ULONG i;
for (i = 0; i < MAX_CLIENTS_CTX_PER_BLOB; i++) {
if (TEST_BIT_OFF(pCfBlock->ClientIndexes, (1 << i)))
break;
}
if (i < MAX_CLIENTS_CTX_PER_BLOB) {
//
// found a zero bit, set it on
//
pCfBlock->ClientIndexes |= (1 << i);
} else {
i = (-1);
}
return i;
}
/*
************************************************************************
ReleaseClientBlock -
Release the client block
Arguments
pClientBlock - the client block to release
Returns
void
************************************************************************
*/
VOID
ReleaseClientBlock(
IN PCLIENT_BLOCK pClientBlock
)
{
NdisFreeSpinLock(&pClientBlock->Lock);
//
// just free the memory
//
GpcFreeToLL(pClientBlock, &ClientLL, ClientTag);
}
/*
************************************************************************
ReleasePatternBlock -
Release the pattern block
Arguments
pPatternBlock - the pattern block to release
Returns
void
************************************************************************
*/
VOID
ReleasePatternBlock(
IN PPATTERN_BLOCK pPatternBlock
)
{
#if DBG
pPatternBlock->TimeToLive = 0xdeadbeef;
#endif
//
// just free the memory
//
GpcFreeToLL(pPatternBlock, &PatternLL, PatternTag);
}
/*
************************************************************************
ReleaseBlobBlock -
Release the blob block
Arguments
pBlobBlock - the blob block to release
Returns
void
************************************************************************
*/
VOID
ReleaseBlobBlock(
IN PBLOB_BLOCK pBlobBlock
)
{
//
// just free the memory
//
GpcFreeMem(pBlobBlock->pClientData, CfInfoDataTag);
ASSERT(pBlobBlock->pNewClientData == NULL);
GpcFreeToLL(pBlobBlock, &CfInfoLL, CfInfoTag);
}
/*
************************************************************************
CreateNewClassificationBlock -
create and return a new classification block for internal use
Arguments
NumEntries - number of entries
Returns
pointer to the new classification block or NULL for no memory resources
************************************************************************
*/
PCLASSIFICATION_BLOCK
CreateNewClassificationBlock(
IN ULONG NumEntries
)
{
PCLASSIFICATION_BLOCK pClassification;
ULONG l;
l = sizeof(CLASSIFICATION_BLOCK) + sizeof(PBLOB_BLOCK) * (NumEntries-1);
GpcAllocMem(&pClassification, l, ClassificationBlockTag);
if (pClassification) {
//
// reset all
//
NdisZeroMemory(pClassification, l);
pClassification->NumberOfElements = NumEntries;
}
return pClassification;
}
/*
************************************************************************
ReleaseClassificationBlock -
Release the Classification block
Arguments
pClassificationBlock - the Classification block to release
Returns
void
************************************************************************
*/
VOID
ReleaseClassificationBlock(
IN PCLASSIFICATION_BLOCK pClassificationBlock
)
{
if (pClassificationBlock) {
//
// release the memory block
//
GpcFreeMem(pClassificationBlock, ClassificationBlockTag);
}
}
/*
************************************************************************
GpcCalcHash -
Calculate the hash table key for a specific pattern
Arguments
ProtocolTempId - The protocol template
pPattern - a pointer to the pattern
Returns
ULONG - the hash key, (-1) if Protocol value is illegal
************************************************************************
*/
ULONG
GpcCalcHash(
IN ULONG ProtocolTempId,
IN PUCHAR pPattern
)
{
ULONG Key = (-1);
ULONG temp;
PULONG Cheat;
PGPC_IP_PATTERN pIpPatt;
PGPC_IPX_PATTERN pIpxPatt;
const ULONG MagicNumber = 0x9e4155b9; // magic number - hocus pocus
TRACE(LOOKUP, ProtocolTempId, pPattern, "GpcClacHash");
ASSERT(pPattern);
switch (ProtocolTempId) {
case GPC_PROTOCOL_TEMPLATE_IP:
//
// the IP protocol template, this function was contributed by
// JohnDo
//
pIpPatt = (PGPC_IP_PATTERN)pPattern;
temp = (pIpPatt->SrcAddr << 16) ^ (pIpPatt->SrcAddr >> 16)
^ pIpPatt->DstAddr ^ pIpPatt->ProtocolId ^ pIpPatt->gpcSpi;
Key = temp * MagicNumber;
break;
case GPC_PROTOCOL_TEMPLATE_IPX:
//
// the IPX protocol template, this function was contributed by
// JohnDo
//
Cheat = (PULONG)pPattern;
temp =
(Cheat[0] << 16) ^ (Cheat[0] >> 16) ^
(Cheat[1] << 16) ^ (Cheat[1] >> 16) ^
(Cheat[2] << 16) ^ (Cheat[2] >> 16) ^
Cheat[3] ^ Cheat[4] ^ Cheat[5];
Key = temp * MagicNumber;
break;
default:
//
// illegal value
//
ASSERT(0);
}
//
// -1 is a bad key
//
if (Key == (-1))
Key = 0;
TRACE(LOOKUP, Key, 0, "GpcClacHash==>");
return Key;
}
/*
************************************************************************
DereferencePattern -
Decrement the RefCount and deletes the pattern block if the count reaches
zero.
Arguments
pPattern - a pointer to the pattern
Returns
void
************************************************************************
*/
VOID
DereferencePattern(
IN PPATTERN_BLOCK pPattern
)
{
ASSERT(pPattern);
//ASSERT(pPattern->RefCount.Count > 0);
TRACE(PATTERN, pPattern, pPattern->DbCtx, "DereferencePattern");
ProtocolStatInc(pPattern->ProtocolTemplate,
DerefPattern2Zero);
ASSERT(IsListEmpty(&pPattern->TimerLinkage));
//
// no longer do we need this CB
//
ReleaseClassificationBlock(pPattern->pClassificationBlock);
//
// time to remove the pattern
//
ReleasePatternBlock(pPattern);
}
/*
************************************************************************
DereferenceBlob -
Decrement the RefCount and deletes the blob block if the count reaches
zero.
Arguments
pBlob - a pointer to the blob
Returns
void
************************************************************************
*/
VOID
DereferenceBlob(
IN PBLOB_BLOCK pBlob
)
{
ASSERT(pBlob);
//ASSERT(*ppBlob);
//TRACE(BLOB, *ppBlob, (*ppBlob)->RefCount, "DereferenceBlob");
//ASSERT((*ppBlob)->RefCount.Count > 0);
CfStatInc(pBlob->pOwnerClient->pCfBlock->AssignedIndex,DerefBlobs2Zero);
//
// time to remove the blob
//
ReleaseBlobBlock(pBlob);
}
/*
************************************************************************
DereferenceClient -
Decrement the RefCount and deletes the client block if the count reaches
zero.
Arguments
pClient - pointer to the client block
Returns
void
************************************************************************
*/
VOID
DereferenceClient(
IN PCLIENT_BLOCK pClient
)
{
PCF_BLOCK pCf;
KIRQL irql;
ASSERT(pClient);
//TRACE(CLIENT, pClient, pClient->RefCount, "DereferenceClient");
//ASSERT(pClient->RefCount.Count > 0);
pCf = pClient->pCfBlock;
RSC_WRITE_LOCK(&pCf->ClientSync, &irql);
//
// time to remove the client
//
GpcRemoveEntryList(&pClient->ClientLinkage);
ReleaseClientIndex(pCf->ClientIndexes, pClient->AssignedIndex);
ReleaseClientBlock(pClient);
RSC_WRITE_UNLOCK(&pCf->ClientSync, irql);
}
/*
************************************************************************
ClientAddCfInfo -
Arguments
Returns
************************************************************************
*/
GPC_STATUS
ClientAddCfInfo(
IN PCLIENT_BLOCK pClient,
IN PBLOB_BLOCK pBlob,
OUT PGPC_CLIENT_HANDLE pClientCfInfoContext
)
{
GPC_STATUS Status = GPC_STATUS_SUCCESS;
DEFINE_KIRQL(dbgIrql);
TRACE(PATTERN, pClient, pBlob, "ClientAddCfInfo");
*pClientCfInfoContext = NULL;
if (pClient->State == GPC_STATE_READY) {
if (pClient->FuncList.ClAddCfInfoNotifyHandler) {
NdisInterlockedIncrement(&pBlob->ClientStatusCountDown);
GET_IRQL(dbgIrql);
TRACE(PATTERN, pClient, dbgIrql, "ClientAddCfInfo (2)");
Status = (pClient->FuncList.ClAddCfInfoNotifyHandler)
(
pClient->ClientCtx,
(GPC_HANDLE)pBlob,
pBlob->ClientDataSize,
pBlob->pClientData,
pClientCfInfoContext
);
VERIFY_IRQL(dbgIrql);
TRACE(PATTERN, *pClientCfInfoContext, Status, "ClientAddCfInfo (3)");
if (Status != GPC_STATUS_PENDING) {
NdisInterlockedDecrement(&pBlob->ClientStatusCountDown);
}
}
}
return Status;
}
/*
************************************************************************
ClientAddCfInfoComplete -
Arguments
Returns
************************************************************************
*/
VOID
ClientAddCfInfoComplete(
IN PCLIENT_BLOCK pClient,
IN PBLOB_BLOCK pBlob,
IN GPC_STATUS Status
)
{
ULONG CfIndex;
DEFINE_KIRQL(dbgIrql);
TRACE(PATTERN, pClient, pBlob, "ClientAddCfInfoComplete");
ASSERT(Status != GPC_STATUS_PENDING);
ASSERT(pClient);
ASSERT(pBlob);
if (pClient->State == GPC_STATE_READY) {
#if NO_USER_PENDING
//
// the user is blocking on this call
//
CTESignal(&pBlob->WaitBlock, Status);
#else
CfIndex = pClient->pCfBlock->AssignedIndex;
if (NT_SUCCESS(Status)) {
CfStatInc(CfIndex,CreatedBlobs);
CfStatInc(CfIndex,CurrentBlobs);
} else {
CfStatInc(CfIndex,RejectedBlobs);
}
if (pClient->FuncList.ClAddCfInfoCompleteHandler) {
GET_IRQL(dbgIrql);
TRACE(PATTERN, pClient, dbgIrql, "ClientAddCfInfoComplete (2)");
TRACE(PATTERN, pClient, pBlob->arClientCtx[pClient->AssignedIndex], "ClientAddCfInfoComplete (3)");
(pClient->FuncList.ClAddCfInfoCompleteHandler)
(
pClient->ClientCtx,
pBlob->arClientCtx[pClient->AssignedIndex],
Status
);
VERIFY_IRQL(dbgIrql);
TRACE(PATTERN, pClient, Status, "ClientAddCfInfoComplete (4)");
} else if (IS_USERMODE_CLIENT(pClient)
&&
pClient == pBlob->pOwnerClient ) {
GET_IRQL(dbgIrql);
TRACE(PATTERN, pClient, dbgIrql, "ClientAddCfInfoComplete (5)");
//
// this is a user mode client - call the specific routine
// to complete a pending IRP, but only if the client is the
// blob owner
//
UMCfInfoComplete( OP_ADD_CFINFO, pClient, pBlob, Status );
VERIFY_IRQL(dbgIrql);
TRACE(PATTERN, pClient, Status, "ClientAddCfInfoComplete (6)");
}
if (NT_SUCCESS(Status)) {
pBlob->State = GPC_STATE_READY;
} else {
//
// remove the blob
//
REFDEL(&pBlob->RefCount, 'BLOB');
}
#endif
}
}
/*
************************************************************************
ClientModifyCfInfoComplete -
Arguments
Returns
************************************************************************
*/
VOID
ClientModifyCfInfoComplete(
IN PCLIENT_BLOCK pClient,
IN PBLOB_BLOCK pBlob,
IN GPC_STATUS Status
)
{
DEFINE_KIRQL(dbgIrql);
TRACE(PATTERN, pClient, pBlob, "ClientModifyCfInfoComplete");
ASSERT(Status != GPC_STATUS_PENDING);
if (pClient->State == GPC_STATE_READY) {
if (pClient->FuncList.ClModifyCfInfoCompleteHandler) {
GET_IRQL(dbgIrql);
TRACE(PATTERN, pClient, dbgIrql, "ClientModifyCfInfoComplete (2)");
(pClient->FuncList.ClModifyCfInfoCompleteHandler)
(
pClient->ClientCtx,
pBlob->arClientCtx[pClient->AssignedIndex],
Status
);
VERIFY_IRQL(dbgIrql);
TRACE(PATTERN, pBlob->arClientCtx[pClient->AssignedIndex], Status, "ClientModifyCfInfoComplete (3)");
} else if (IS_USERMODE_CLIENT(pClient)) {
GET_IRQL(dbgIrql);
TRACE(PATTERN, pClient, dbgIrql, "ClientModifyCfInfoComplete (4)");
UMCfInfoComplete( OP_MODIFY_CFINFO, pClient, pBlob, Status );
VERIFY_IRQL(dbgIrql);
TRACE(PATTERN, pBlob->arClientCtx[pClient->AssignedIndex], Status, "ClientModifyCfInfoComplete (5)");
}
}
}
/*
************************************************************************
ClientModifyCfInfo -
Arguments
Returns
************************************************************************
*/
GPC_STATUS
ClientModifyCfInfo(
IN PCLIENT_BLOCK pClient,
IN PBLOB_BLOCK pBlob,
IN ULONG CfInfoSize,
IN PVOID pClientData
)
{
GPC_STATUS Status = GPC_STATUS_IGNORED;
DEFINE_KIRQL(dbgIrql);
TRACE(PATTERN, pClient, pBlob, "ClientModifyCfInfo");
if (pClient->State == GPC_STATE_READY) {
if (pClient->FuncList.ClModifyCfInfoNotifyHandler) {
NdisInterlockedIncrement(&pBlob->ClientStatusCountDown);
GET_IRQL(dbgIrql);
TRACE(PATTERN, pClient, dbgIrql, "ClientModifyCfInfo (2)");
Status = (pClient->FuncList.ClModifyCfInfoNotifyHandler)
(pClient->ClientCtx,
pBlob->arClientCtx[pClient->AssignedIndex],
CfInfoSize,
pClientData
);
VERIFY_IRQL(dbgIrql);
TRACE(PATTERN, pBlob->arClientCtx[pClient->AssignedIndex], Status, "ClientModifyCfInfo (3)");
if (Status != GPC_STATUS_PENDING) {
NdisInterlockedDecrement(&pBlob->ClientStatusCountDown);
}
}
}
return Status;
}
/*
************************************************************************
ClientRemoveCfInfoComplete -
Arguments
Returns
************************************************************************
*/
VOID
ClientRemoveCfInfoComplete(
IN PCLIENT_BLOCK pClient,
IN PBLOB_BLOCK pBlob,
IN GPC_STATUS Status
)
{
ULONG CfIndex;
DEFINE_KIRQL(dbgIrql);
TRACE(PATTERN, pClient, pBlob, "ClientRemoveCfInfoComplete");
ASSERT(Status != GPC_STATUS_PENDING);
ASSERT(pClient);
ASSERT(pBlob);
#if NO_USER_PENDING
//
// the user is blocking on this call
//
CTESignal(&pBlob->WaitBlock, Status);
#else
CfIndex = pClient->pCfBlock->AssignedIndex;
if (NT_SUCCESS(Status)) {
CfStatInc(CfIndex,DeletedBlobs);
CfStatDec(CfIndex,CurrentBlobs);
}
if (pClient->FuncList.ClRemoveCfInfoCompleteHandler) {
GET_IRQL(dbgIrql);
TRACE(PATTERN, pClient, pBlob->arClientCtx[pClient->AssignedIndex], "ClientRemoveCfInfoComplete (2)");
(pClient->FuncList.ClRemoveCfInfoCompleteHandler)
(
pClient->ClientCtx,
pBlob->arClientCtx[pClient->AssignedIndex],
Status
);
VERIFY_IRQL(dbgIrql);
TRACE(PATTERN, pClient, Status, "ClientRemoveCfInfoComplete (3)");
} else if (IS_USERMODE_CLIENT(pClient)) {
GET_IRQL(dbgIrql);
TRACE(PATTERN, pClient, pBlob->arClientCtx[pClient->AssignedIndex], "ClientRemoveCfInfoComplete (4)");
UMCfInfoComplete( OP_REMOVE_CFINFO, pClient, pBlob, Status );
VERIFY_IRQL(dbgIrql);
TRACE(PATTERN, pClient, Status, "ClientRemoveCfInfoComplete (5)");
}
#endif
}
/*
************************************************************************
ClientRemoveCfInfo -
Arguments
Returns
************************************************************************
*/
GPC_STATUS
ClientRemoveCfInfo(
IN PCLIENT_BLOCK pClient,
IN PBLOB_BLOCK pBlob,
IN GPC_CLIENT_HANDLE ClientCfInfoContext
)
{
GPC_STATUS Status = GPC_STATUS_SUCCESS;
DEFINE_KIRQL(dbgIrql);
TRACE(PATTERN, pClient, pBlob, "ClientRemoveCfInfo");
if (pClient->State == GPC_STATE_READY) {
if (pClient->FuncList.ClRemoveCfInfoNotifyHandler) {
NdisInterlockedIncrement(&pBlob->ClientStatusCountDown);
GET_IRQL(dbgIrql);
TRACE(PATTERN, pClient, ClientCfInfoContext, "ClientRemoveCfInfo (2)");
Status = (pClient->FuncList.ClRemoveCfInfoNotifyHandler)
(pClient->ClientCtx,
ClientCfInfoContext
);
VERIFY_IRQL(dbgIrql);
TRACE(PATTERN, pClient, Status, "ClientRemoveCfInfo (3)");
if (Status != GPC_STATUS_PENDING) {
NdisInterlockedDecrement(&pBlob->ClientStatusCountDown);
}
} else if (IS_USERMODE_CLIENT(pClient)
&&
pClient == pBlob->pOwnerClient) {
GET_IRQL(dbgIrql);
TRACE(PATTERN, pClient, ClientCfInfoContext, "ClientRemoveCfInfo (4)");
//
// the notified client installed the blob
// and it is a user mode client
// we need to make a special call to dequeue a pending IRP
// and complete it with the specified data
//
UMClientRemoveCfInfoNotify(pClient, pBlob);
VERIFY_IRQL(dbgIrql);
TRACE(PATTERN, pClient, Status, "ClientRemoveCfInfo (5)");
}
}
return Status;
}
/*
************************************************************************
ClearPatternLinks -
Arguments
Returns
************************************************************************
*/
VOID
ClearPatternLinks(
IN PPATTERN_BLOCK pPattern,
IN PPROTOCOL_BLOCK pProtocol,
IN ULONG CfIndex
)
{
PBLOB_BLOCK *ppBlob;
//
// Remove the pattern from the blob list
// and NULL the pointer to the blob in the pattern block
//
ppBlob = & GetBlobFromPattern(pPattern, CfIndex);
if (*ppBlob) {
NDIS_LOCK(&(*ppBlob)->Lock);
GpcRemoveEntryList(&pPattern->BlobLinkage[CfIndex]);
NDIS_UNLOCK(&(*ppBlob)->Lock);
*ppBlob = NULL;
}
}
/*
************************************************************************
ModifyCompleteClients -
Arguments
Returns
************************************************************************
*/
VOID
ModifyCompleteClients(
IN PCLIENT_BLOCK pClient,
IN PBLOB_BLOCK pBlob
)
{
uint i;
PCLIENT_BLOCK pNotifyClient;
KIRQL irql;
if (NT_SUCCESS(pBlob->LastStatus)) {
//
// in case of successful completion, assign the
// new client data
//
NDIS_LOCK(&pBlob->Lock);
WRITE_LOCK(&glData.ChLock, &irql);
GpcFreeMem(pBlob->pClientData, CfInfoDataTag);
pBlob->ClientDataSize = pBlob->NewClientDataSize;
pBlob->pClientData = pBlob->pNewClientData;
WRITE_UNLOCK(&glData.ChLock, irql);
NDIS_UNLOCK(&pBlob->Lock);
} else {
GpcFreeMem(pBlob->pNewClientData, CfInfoDataTag);
}
pBlob->NewClientDataSize = 0;
pBlob->pNewClientData = NULL;
//
// notify each client (except the caller) that successfully
// modified the blob about the status.
// it can be SUCCESS or some failure
//
for (i = 0; i < MAX_CLIENTS_CTX_PER_BLOB; i++) {
//
// only clients with none zero entries
// have been succefully modified the blob
//
if (pNotifyClient = pBlob->arpClientStatus[i]) {
//
// complete here
//
ClientModifyCfInfoComplete(
pNotifyClient,
pBlob,
pBlob->LastStatus
);
//
// release the one we got earlier
//
//DereferenceClient(pNotifyClient);
}
} // for
#if 0
//
// now, complete the call back to the calling client
//
ClientModifyCfInfoComplete(
pBlob->pCallingClient,
pBlob,
pBlob->LastStatus
);
#endif
pBlob->State = GPC_STATE_READY;
}
#if 0
/*
************************************************************************
GetClassificationHandle -
Get the classification handle from the blob. If none is available
creates a new one. '0' is not a valid CH!
Arguments
pClient - The calling client
pPattern - The pattern that refers to the CH
Returns
A classification handle
************************************************************************
*/
CLASSIFICATION_HANDLE
GetClassificationHandle(
IN PCLIENT_BLOCK pClient,
IN PPATTERN_BLOCK pPattern
)
{
HFHandle hfh;
ULONG t;
PCLASSIFICATION_BLOCK pCB;
TRACE(CLASSIFY, pClient, pPattern, "GetClassificationHandle:");
if (TEST_BIT_ON(pPattern->Flags,PATTERN_SPECIFIC)) {
//
// this is a specific pattern
//
//
// get the CH from it
//
ASSERT(pPattern->pClassificationBlock);
hfh = pPattern->pClassificationBlock->ClassificationHandle;
//
// check if CH is valid
//
t = pPattern->ProtocolTemplate;
pCB = (PCLASSIFICATION_BLOCK)dereference_HF_handle(glData.pCHTable,
hfh);
TRACE(CLASSHAND, pCB, hfh, "GetClassificationHandle (~)");
if (pCB != pPattern->pClassificationBlock) {
//
// the CH is invalid, release it and get a new one
//
NDIS_LOCK(&glData.Lock);
release_HF_handle(glData.pCHTable, hfh);
ProtocolStatInc(pPattern->ProtocolTemplate,
RemovedCH);
TRACE(CLASSHAND, glData.pCHTable, hfh, "GetClassificationHandle (-)");
hfh = assign_HF_handle(glData.pCHTable,
(void *)pPattern->pClassificationBlock);
ProtocolStatInc(pPattern->ProtocolTemplate,
InsertedCH);
NDIS_UNLOCK(&glData.Lock);
TRACE(CLASSIFY, pPattern, hfh, "GetClassificationHandle (+)");
pPattern->pClassificationBlock->ClassificationHandle = hfh;
}
} else {
//
// this is a generic pattern
//
hfh = 0;
}
TRACE(CLASSIFY, pPattern, hfh, "GetClassificationHandle==>");
return (CLASSIFICATION_HANDLE)hfh;
}
#endif
/*
************************************************************************
FreeClassificationHandle -
Free the classification handle. It will invalidate the entry in the
index table and make it avaiable for future use.
Arguments
pClient - The calling client
CH - The classification handle
Returns
void
************************************************************************
*/
VOID
FreeClassificationHandle(
IN PCLIENT_BLOCK pClient,
IN CLASSIFICATION_HANDLE CH
)
{
KIRQL CHirql;
WRITE_LOCK(&glData.ChLock, &CHirql);
release_HF_handle(glData.pCHTable, CH);
TRACE(CLASSHAND, glData.pCHTable, CH, "FreeClassificationHandle");
WRITE_UNLOCK(&glData.ChLock, CHirql);
}
GPC_STATUS
CleanupBlobs(
IN PCLIENT_BLOCK pClient
)
{
PBLOB_BLOCK pBlob;
//PPATTERN_BLOCK pPattern;
//ULONG CfIndex = pClient->pCfBlock->AssignedIndex;
GPC_STATUS Status = GPC_STATUS_SUCCESS;
NDIS_LOCK(&pClient->Lock);
//
// scan blobs
//
while (!IsListEmpty(&pClient->BlobList)) {
//
// get the blob
//
pBlob = CONTAINING_RECORD(pClient->BlobList.Flink, BLOB_BLOCK, ClientLinkage);
pBlob->Flags |= PATTERN_REMOVE_CB_BLOB;
NDIS_UNLOCK(&pClient->Lock);
//
// remove the blob
//
Status = GpcRemoveCfInfo((GPC_HANDLE)pClient,
(GPC_HANDLE)pBlob
);
NDIS_LOCK(&pClient->Lock);
}
NDIS_UNLOCK(&pClient->Lock);
return GPC_STATUS_SUCCESS;
}
VOID
CloseAllObjects(
IN PFILE_OBJECT FileObject,
IN PIRP Irp
)
{
PLIST_ENTRY pEntry0, pHead0;
PLIST_ENTRY pEntry, pHead;
PCLIENT_BLOCK pClient = NULL;
PCF_BLOCK pCf;
PPROTOCOL_BLOCK pProtocol;
//int i,j;
//NTSTATUS NtStatus;
//QUEUED_COMPLETION QItem;
KIRQL irql;
NDIS_LOCK(&glData.Lock);
pHead0 = &glData.CfList;
pEntry0 = pHead0->Flink;
while (pEntry0 != pHead0 && pClient == NULL) {
pCf = CONTAINING_RECORD(pEntry0, CF_BLOCK, Linkage);
pEntry0 = pEntry0->Flink;
RSC_READ_LOCK(&pCf->ClientSync, &irql);
pHead = &pCf->ClientList;
pEntry = pHead->Flink;
while (pEntry != pHead && pClient == NULL) {
pClient = CONTAINING_RECORD(pEntry,CLIENT_BLOCK,ClientLinkage);
pEntry = pEntry->Flink;
if (pClient->pFileObject == FileObject) {
REFADD(&pClient->RefCount, 'CAOB');
} else {
pClient = NULL;
}
}
RSC_READ_UNLOCK(&pCf->ClientSync, irql);
} // while (...)
NDIS_UNLOCK(&glData.Lock);
if (pClient) {
//
// clear all the blobs on the client
//
CleanupBlobs(pClient);
//
// deregister the client
//
GpcDeregisterClient((GPC_HANDLE)pClient);
//
// release the previous ref count
//
REFDEL(&pClient->RefCount, 'CAOB');
}
}
// Cool new feature - Timer Wheels [ShreeM]
// We maintain N lists of patterns, one for each "timertick". The Pattern
// Expiry routine will clean up one of the lists every time it is invoked.
// It then makes a note to cleanup the next list on the wheel, the next time
// it is invoked.
// The Timer Wheels reduces spin lock contention between inserts and deletes.
VOID
PatternTimerExpired(
IN PVOID SystemSpecific1,
IN PVOID FunctionContext,
IN PVOID SystemSpecific2,
IN PVOID SystemSpecific3
)
{
PLIST_ENTRY pEntry;
PPATTERN_BLOCK pPattern;
PCF_BLOCK pCf;
ULONG CleanupWheelIndex = 0, NewWheelIndex;
PPROTOCOL_BLOCK pProtocol = &glData.pProtocols[PtrToUlong(FunctionContext)];
TRACE(PAT_TIMER, FunctionContext, 0, "PatternTimerExpired");
DBGPRINT(PAT_TIMER, ("PatternTimerExpired: Timer expired, protocol=%d \n",
PtrToUlong(FunctionContext)));
//
// Which of the timer wheels do we want to cleanup this time?
// Remember that we Increment the current index pointer into the wheels
// All the wheel index calculations are protected by gldata->lock.
NDIS_LOCK(&glData.Lock);
CleanupWheelIndex = pProtocol->CurrentWheelIndex;
pProtocol->CurrentWheelIndex += 1;
//
// Make sure we wrap around.
//
pProtocol->CurrentWheelIndex %= NUMBER_OF_WHEELS;
NDIS_UNLOCK(&glData.Lock);
NDIS_LOCK(&pProtocol->PatternTimerLock[CleanupWheelIndex]);
while (!IsListEmpty(&pProtocol->TimerPatternList[CleanupWheelIndex])) {
pEntry = RemoveHeadList(&pProtocol->TimerPatternList[CleanupWheelIndex]);
pPattern = CONTAINING_RECORD(pEntry, PATTERN_BLOCK, TimerLinkage);
NDIS_UNLOCK(&pProtocol->PatternTimerLock[CleanupWheelIndex]);
ASSERT(pPattern->TimeToLive != 0xdeadbeef);
ASSERT(TEST_BIT_ON( pPattern->Flags, PATTERN_AUTO ));
NDIS_LOCK(&pPattern->Lock);
pPattern->Flags |= ~PATTERN_AUTO;
NDIS_UNLOCK(&pPattern->Lock);
InitializeListHead(&pPattern->TimerLinkage);
pCf = pPattern->pAutoClient->pCfBlock;
TRACE(PAT_TIMER, pPattern, pPattern->RefCount.Count, "PatternTimerExpired: del");
ProtocolStatInc(pPattern->ProtocolTemplate,
DeletedAp);
ProtocolStatDec(pPattern->ProtocolTemplate,
CurrentAp);
//
// actually remove the pattern
//
DBGPRINT(PAT_TIMER, ("PatternTimerExpired: removing pattern=%X, ref=%d, client=%X \n",
pPattern, pPattern->RefCount, pPattern->pAutoClient));
GpcRemovePattern((GPC_HANDLE)pPattern->pAutoClient,
(GPC_HANDLE)pPattern);
InterlockedDecrement(&pProtocol->AutoSpecificPatternCount);
NDIS_LOCK(&pProtocol->PatternTimerLock[CleanupWheelIndex]);
}
NDIS_UNLOCK(&pProtocol->PatternTimerLock[CleanupWheelIndex]);
//
// If there are any Auto Specific patterns around restart the timer.
//
if(InterlockedExchangeAdd(&pProtocol->AutoSpecificPatternCount, 0) > 0) {
NdisSetTimer(&pProtocol->PatternTimer, PATTERN_TIMEOUT);
DBGPRINT(PAT_TIMER, ("PatternTimer restarted\n"));
} else {
DBGPRINT(PAT_TIMER, ("Zero Auto Patterns - Timer NOT restarted\n"));
}
}
GPC_STATUS
AddSpecificPatternWithTimer(
IN PCLIENT_BLOCK pClient,
IN ULONG ProtocolTemplate,
IN PVOID PatternKey,
OUT PPATTERN_BLOCK *ppPattern,
OUT PCLASSIFICATION_HANDLE pClassificationHandle
)
{
GPC_STATUS Status;
PPATTERN_BLOCK pPattern, pCreatedPattern;
PPROTOCOL_BLOCK pProtocol = &glData.pProtocols[ProtocolTemplate];
UCHAR Mask[MAX_PATTERN_SIZE];
ULONG WheelIndex = 0;
TRACE(PAT_TIMER, pClient, PatternKey, "AddSpecificPatternWithTimer");
#if DBG
{
PGPC_IP_PATTERN pIp = (PGPC_IP_PATTERN)PatternKey;
DBGPRINT(PAT_TIMER, ("AddSpecificPatternWithTimer: Client=%X \n", pClient));
#if INTERFACE_ID
DBGPRINT(PAT_TIMER, ("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]
));
#endif
}
#endif
RtlFillMemory(Mask, sizeof(Mask), 0xff);
pPattern = CreateNewPatternBlock(PATTERN_SPECIFIC);
pCreatedPattern = pPattern;
if (pPattern) {
//
// setup the pattern fields and add it
//
//pPattern->RefCount++;
pPattern->Priority = 0;
pPattern->ProtocolTemplate = ProtocolTemplate;
pPattern->Flags |= PATTERN_AUTO;
pPattern->pAutoClient = pClient;
Status = AddSpecificPattern(
pClient,
PatternKey,
Mask,
NULL,
pProtocol,
&pPattern, // output pattern pointer
pClassificationHandle
);
} else {
Status = GPC_STATUS_NO_MEMORY;
}
if (NT_SUCCESS(Status)) {
//
// we didn't get an already existing pattern
//
//ASSERT(*pClassificationHandle);
*ppPattern = pPattern;
// Figure out which wheel to stick this pattern on.
NDIS_LOCK(&glData.Lock);
WheelIndex = pProtocol->CurrentWheelIndex;
NDIS_UNLOCK(&glData.Lock);
WheelIndex += (NUMBER_OF_WHEELS -1);
WheelIndex %= NUMBER_OF_WHEELS;
//
// we must lock this pattern since we look at the timer linkage
//
NDIS_LOCK(&pPattern->Lock);
//
// set the AUTO flag again, since we might have got
// a pattern that already exist
//
pPattern->Flags |= PATTERN_AUTO;
pPattern->pAutoClient = pClient;
pPattern->WheelIndex = WheelIndex;
//
// this pattern has not been on any the timer list yet
//
if (IsListEmpty(&pPattern->TimerLinkage)) {
//
// We need to insert this in the TimerWheel which is (NUMBER_OF_WHEELS - 1)
// away from the current, so that it spends enough time on the list.
//
NDIS_DPR_LOCK(&pProtocol->PatternTimerLock[WheelIndex]);
//
// If the AutoSpecificPatternCount was zero earlier, then we need
// to a) start the timer and b) increment this count.
//
if (1 == InterlockedIncrement(&pProtocol->AutoSpecificPatternCount)) {
//
// restart the timer for the first auto pattern
//
NdisSetTimer(&pProtocol->PatternTimer, PATTERN_TIMEOUT);
TRACE(PAT_TIMER, pPattern, PATTERN_TIMEOUT, "Starting Pattern Timer\n AddSpecificPatternWithTimer: (1)");
}
GpcInsertHeadList(&pProtocol->TimerPatternList[WheelIndex], &pPattern->TimerLinkage);
//
// don't refer to pPattern after it has been placed on the timer list
// since the timer may expire any time and remove it from there...
//
NDIS_DPR_UNLOCK(&pProtocol->PatternTimerLock[WheelIndex]);
}
//
// This is a specific pattern, so lets increment the count [ShreeM].
InterlockedIncrement(&pProtocol->SpecificPatternCount);
NDIS_UNLOCK(&pPattern->Lock);
ProtocolStatInc(ProtocolTemplate,
CreatedAp);
ProtocolStatInc(ProtocolTemplate,
CurrentAp);
} else {
*ppPattern = NULL;
*pClassificationHandle = 0;
ProtocolStatInc(ProtocolTemplate,
RejectedAp);
}
if (pPattern) {
//
// release the reference count to this pattern
// in case of an error, this will also release
// the data block
//
REFDEL(&pCreatedPattern->RefCount, 'FILT');
}
TRACE(PAT_TIMER, pPattern, Status, "AddSpecificPatternWithTimer==>");
DBGPRINT(CLASSIFY, ("AddSpecificPatternWithTimer: pClient=%X Pattern=%X Status=%X\n",
pClient, pPattern, Status));
return Status;
}
NTSTATUS
InitPatternTimer(
IN ULONG ProtocolTemplate
)
{
ULONG i=0;
//
// We increase the granularity of when a "Automatic" Pattern gets cleaned
// out by using timer wheels, but they are more efficient for inserting and
// removing (in terms of locks).
//
for (i = 0; i < NUMBER_OF_WHEELS; i++) {
NDIS_INIT_LOCK(&glData.pProtocols[ProtocolTemplate].PatternTimerLock[i]);
InitializeListHead(&glData.pProtocols[ProtocolTemplate].TimerPatternList[i]);
}
glData.pProtocols[ProtocolTemplate].CurrentWheelIndex = 0;
NdisInitializeTimer(&glData.pProtocols[ProtocolTemplate].PatternTimer,
PatternTimerExpired,
(PVOID) ULongToPtr(ProtocolTemplate));
return STATUS_SUCCESS;
}
//
// Some CRT and RTL functions that cant be used at DISPATHC_LEVEL IRQL are being
// cut/paste here.
//