/* ************************************************************************ 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. //