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.
2280 lines
55 KiB
2280 lines
55 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,
|
|
BOOLEAN fChargeQuota // Should I charge Quota?
|
|
)
|
|
{
|
|
// Quota Charging should be done only if we have a proces context
|
|
|
|
PBLOB_BLOCK pBlob;
|
|
|
|
|
|
if (fChargeQuota){
|
|
GpcAllocMemWithQuota(&pBlob,CfInfoLLSize,CfInfoTag);
|
|
}
|
|
else{
|
|
GpcAllocMem(&pBlob,CfInfoLLSize,CfInfoTag);
|
|
}
|
|
|
|
|
|
|
|
if (pBlob) {
|
|
|
|
//
|
|
// reset all
|
|
//
|
|
|
|
NdisZeroMemory(pBlob, sizeof(BLOB_BLOCK));
|
|
|
|
|
|
if (fChargeQuota){
|
|
GpcAllocMemWithQuota(&pBlob->pClientData,
|
|
ClientDataSize, CfInfoDataTag);
|
|
}
|
|
else{
|
|
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);
|
|
GpcFreeMem(pBlob,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);
|
|
GpcFreeMem(pBlobBlock,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);
|
|
//
|
|
// If there is a File Object, dereference it.
|
|
//
|
|
if (pBlob->FileObject) {
|
|
ObDereferenceObject(pBlob->FileObject);
|
|
pBlob->FileObject = NULL;
|
|
}
|
|
|
|
if (pBlob->Pattern) {
|
|
GpcFreeMem(pBlob->Pattern,TcpPatternTag);
|
|
pBlob->Pattern = NULL;
|
|
}
|
|
|
|
|
|
//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)");
|
|
|
|
// Pass in link id if a client of the new interface registers
|
|
if (IS_USERMODE_CLIENT_EX(pBlob->pOwnerClient)){
|
|
Status = (pClient->FuncList.ClAddCfInfoNotifyHandler)
|
|
(
|
|
pClient->ClientCtx,
|
|
(GPC_HANDLE)pBlob,
|
|
&(pBlob->Pattern->InterfaceId),
|
|
pBlob->ClientDataSize,
|
|
pBlob->pClientData,
|
|
pClientCfInfoContext
|
|
);
|
|
}
|
|
else{
|
|
|
|
Status = (pClient->FuncList.ClAddCfInfoNotifyHandler)
|
|
(
|
|
pClient->ClientCtx,
|
|
(GPC_HANDLE)pBlob,
|
|
NULL,
|
|
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) //For client using IOCTL interface
|
|
&&
|
|
!IS_USERMODE_CLIENT_EX(pClient)//But Not for new IOCTL interfaces
|
|
&&
|
|
pClient == pBlob->pOwnerClient) {// If the client owns the Blob
|
|
|
|
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;
|
|
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])) {
|
|
|
|
PCLIENT_BLOCK pClient;
|
|
|
|
pEntry = RemoveHeadList(&pProtocol->TimerPatternList[CleanupWheelIndex]);
|
|
|
|
pPattern = CONTAINING_RECORD(pEntry, PATTERN_BLOCK, TimerLinkage);
|
|
|
|
InitializeListHead(&pPattern->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);
|
|
|
|
|
|
|
|
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));
|
|
|
|
pClient = pPattern->pAutoClient;
|
|
|
|
GpcRemovePattern((GPC_HANDLE)pPattern->pAutoClient,
|
|
(GPC_HANDLE)pPattern);
|
|
|
|
REFDEL(&(pClient->RefCount), 'CLNT');
|
|
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=GPC_STATUS_SUCCESS;
|
|
PPATTERN_BLOCK pPattern=NULL, pCreatedPattern=NULL;
|
|
PPROTOCOL_BLOCK pProtocol = &glData.pProtocols[ProtocolTemplate];
|
|
UCHAR Mask[MAX_PATTERN_SIZE];
|
|
ULONG WheelIndex = 0;
|
|
ULONG ulCurrentAutoPatternCount=0;
|
|
|
|
|
|
ulCurrentAutoPatternCount=InterlockedExchangeAdd(&pProtocol->AutoSpecificPatternCount,0);
|
|
DBGPRINT(PAT_TIMER,("MSGPC:Creating New AutoPattern: Number of AutoPatterns"
|
|
"Before Creation = %ul \n", ulCurrentAutoPatternCount));
|
|
|
|
if (ulCurrentAutoPatternCount > glData.AutoPatternLimit) {
|
|
DBGPRINT(PAT_TIMER,("MSGPCHit AutoPatternLimit : Num AutoPatterns = %ul :"
|
|
"Limit =%ul \n",ulCurrentAutoPatternCount, glData.AutoPatternLimit));
|
|
Status = GPC_STATUS_NO_MEMORY;
|
|
goto exit;
|
|
}
|
|
|
|
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;
|
|
// This flag indicates that the auto pattern is not on
|
|
// timer list yet . This means
|
|
// the pattern is not ready yet though it may or may
|
|
// not have been inserted into the patternhashtable
|
|
pPattern->Flags |= PATTERN_AUTO_NOT_READY;
|
|
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);
|
|
// Pattern is now ready. It has been inserted
|
|
// into the hash table and has been put into the
|
|
// timer list.
|
|
pPattern->Flags &= ~PATTERN_AUTO_NOT_READY;
|
|
|
|
NDIS_UNLOCK(&pPattern->Lock);
|
|
|
|
ProtocolStatInc(ProtocolTemplate,
|
|
CreatedAp);
|
|
|
|
ProtocolStatInc(ProtocolTemplate,
|
|
CurrentAp);
|
|
} else {
|
|
|
|
|
|
goto exit;
|
|
}
|
|
|
|
|
|
|
|
exit:
|
|
if (!NT_SUCCESS(Status)){
|
|
*ppPattern = NULL;
|
|
*pClassificationHandle = 0;
|
|
ProtocolStatInc(ProtocolTemplate,
|
|
RejectedAp);
|
|
}
|
|
else{
|
|
REFADD(&pClient->RefCount, 'CLNT');
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
// SS202 CR
|
|
//
|
|
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.
|
|
//
|
|
|
|
|
|
|
|
NTSTATUS
|
|
OpenRegKey(
|
|
PHANDLE HandlePtr,
|
|
PWCHAR KeyName
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Opens a Registry key and returns a handle to it.
|
|
|
|
Arguments:
|
|
|
|
HandlePtr - The varible into which to write the opened handle.
|
|
KeyName - The name of the Registry key to open.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS or an appropriate failure code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
OBJECT_ATTRIBUTES ObjectAttributes;
|
|
UNICODE_STRING UKeyName;
|
|
|
|
PAGED_CODE();
|
|
|
|
RtlInitUnicodeString(&UKeyName, KeyName);
|
|
|
|
memset(&ObjectAttributes, 0, sizeof(OBJECT_ATTRIBUTES));
|
|
InitializeObjectAttributes(&ObjectAttributes,
|
|
&UKeyName,
|
|
OBJ_CASE_INSENSITIVE,
|
|
NULL,
|
|
NULL);
|
|
|
|
Status = ZwOpenKey(HandlePtr,
|
|
KEY_READ,
|
|
&ObjectAttributes);
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
NTSTATUS
|
|
GetRegDWORDValue(
|
|
HANDLE KeyHandle,
|
|
PWCHAR ValueName,
|
|
PULONG ValueData
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reads a REG_DWORD value from the registry into the supplied variable.
|
|
|
|
Arguments:
|
|
|
|
KeyHandle - Open handle to the parent key of the value to read.
|
|
ValueName - The name of the value to read.
|
|
ValueData - The variable into which to read the data.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS or an appropriate failure code.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
ULONG resultLength;
|
|
PKEY_VALUE_FULL_INFORMATION keyValueFullInformation;
|
|
UCHAR keybuf[WORK_BUFFER_SIZE];
|
|
UNICODE_STRING UValueName;
|
|
|
|
PAGED_CODE();
|
|
|
|
RtlInitUnicodeString(&UValueName, ValueName);
|
|
|
|
keyValueFullInformation = (PKEY_VALUE_FULL_INFORMATION)keybuf;
|
|
RtlZeroMemory(keyValueFullInformation, sizeof(keyValueFullInformation));
|
|
|
|
|
|
status = ZwQueryValueKey(KeyHandle,
|
|
&UValueName,
|
|
KeyValueFullInformation,
|
|
keyValueFullInformation,
|
|
WORK_BUFFER_SIZE,
|
|
&resultLength);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
if (keyValueFullInformation->Type != REG_DWORD) {
|
|
status = STATUS_INVALID_PARAMETER_MIX;
|
|
} else {
|
|
*ValueData = *((ULONG UNALIGNED *)((PCHAR)keyValueFullInformation +
|
|
keyValueFullInformation->DataOffset));
|
|
}
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reads a REG_DWORD value from registry and init the variable passed in..
|
|
|
|
Arguments:
|
|
|
|
- Open handle to the parent key of the value to read.
|
|
param - The name of the value to read.
|
|
ValueData - The variable into which to read the data.
|
|
|
|
Return Value:
|
|
|
|
STATUS_SUCCESS or an appropriate failure code.
|
|
|
|
--*/
|
|
VOID
|
|
GPC_REG_READ_DWORD(HANDLE hRegKey, PWCHAR pwcName, PULONG pulData, ULONG ulDefault,ULONG ulMax, ULONG ulMin) {
|
|
NTSTATUS status;
|
|
status = GetRegDWORDValue(hRegKey,
|
|
pwcName,
|
|
(pulData));
|
|
|
|
if (!NT_SUCCESS(status)) {
|
|
*(pulData) = ulDefault;
|
|
} else if (*(pulData) > ulMax) {
|
|
*(pulData) = ulMax;
|
|
} else if (*(pulData) < ulMin) {
|
|
*(pulData) = ulMin;
|
|
}
|
|
}
|
|
|
|
VOID
|
|
GpcReadRegistry()
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Reads config info from registry into glData
|
|
|
|
Arguments:
|
|
|
|
|
|
Return Value:
|
|
|
|
status of the read.
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS status;
|
|
HANDLE hRegKey;
|
|
WCHAR GpcParametersRegistryKey[] = GPC_REG_KEY;
|
|
|
|
glData.SystemSizeHint = MmQuerySystemSize();
|
|
switch (glData.SystemSizeHint)
|
|
{
|
|
case MmSmallSystem:
|
|
glData.AutoPatternLimit = DEFAULT_SMALL_SYSTEM_AUTO_PATTERN_LIMIT;
|
|
break;
|
|
|
|
case MmMediumSystem:
|
|
glData.AutoPatternLimit = DEFAULT_MEDIUM_SYSTEM_AUTO_PATTERN_LIMIT;
|
|
break;
|
|
|
|
case MmLargeSystem:
|
|
glData.AutoPatternLimit = DEFAULT_LARGE_SYSTEM_AUTO_PATTERN_LIMIT;
|
|
break;
|
|
|
|
default: break;
|
|
}
|
|
|
|
status = OpenRegKey(&hRegKey,
|
|
GpcParametersRegistryKey);
|
|
|
|
if (NT_SUCCESS(status)) {
|
|
//
|
|
// Expected configuration values. We use reasonable defaults if they
|
|
// aren't available for some reason.
|
|
//
|
|
GPC_REG_READ_DWORD( hRegKey,
|
|
GPC_REG_AUTO_PATTERN_LIMIT,
|
|
&glData.AutoPatternLimit,
|
|
glData.AutoPatternLimit,
|
|
GPC_AUTO_PATTERN_MAX,
|
|
GPC_AUTO_PATTERN_MIN);
|
|
}
|
|
ZwClose(hRegKey);
|
|
}
|