mirror of https://github.com/tongzx/nt5src
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
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.
|
|
//
|
|
|