/*********************************************************************/ /** Microsoft Generic Packet Scheduler **/ /** Copyright(c) Microsoft Corp., 1996-1997 **/ /********************************************************************/ #ifndef __GPCDEF #define __GPCDEF //*** gpcdef.h - GPC internal definitions & prototypes // // This file containes all the GPC data structures & defines /* ///////////////////////////////////////////////////////////////// // // defines // ///////////////////////////////////////////////////////////////// */ // // Max number of clients per blob (same CF) // // AbhisheV - This can not be more than sizeof(ULONG)*8. // #define MAX_CLIENTS_CTX_PER_BLOB 32 // // Max pattern size, // GPC_IP_PATTERN = 24 bytes // GPC_IPX_PATTERN = 24 bytes // #define MAX_PATTERN_SIZE sizeof(GPC_IP_PATTERN) extern BOOLEAN IsItChanging; // // Pattern flags // #define PATTERN_SPECIFIC 0x00000001 #define PATTERN_AUTO 0x00000002 #define PATTERN_REMOVE_CB_BLOB 0x00000004 // Following flag to be set and unset only in addspecificpatternwithtimer. // It indicates pattern has been created but not on timer list yet. // It is set before inserting it into the hash table i.e calling // AddSpecificPattern. // It is supposed to be reset after putting pattern on timer list // which in turn should occur after the pattern has been added into // the hash table i.e. a successful call to addspecificpattern #define PATTERN_AUTO_NOT_READY 0x00000008 // // Auto Pattern defines // // Every PATTERN_TIMEOUT seconds, the PatternTimerExpiry Routine gets called. #define PATTERN_TIMEOUT 60000 // 60 seconds // This is the amount of time that a Pattern created for optimization // lives on the Pattern List. #define AUTO_PATTERN_ENTRY_TIMEOUT 300000 // 5 minutes // This is the number of timer granularity. #define NUMBER_OF_WHEELS (AUTO_PATTERN_ENTRY_TIMEOUT/PATTERN_TIMEOUT) // // The size of structure to be allocated for TCP query with 1 address #define ROUTING_INFO_ADDR_1_SIZE \ FIELD_OFFSET(GPC_TCP_QUERY_CONTEXT ,RouteInfo) + \ FIELD_OFFSET(TDI_ROUTING_INFO, Address) + \ FIELD_OFFSET(TRANSPORT_ADDRESS, Address) + \ FIELD_OFFSET(TA_ADDRESS, Address) + sizeof(TDI_ADDRESS_IP) // // For 2 addresses #define ROUTING_INFO_ADDR_2_SIZE ROUTING_INFO_ADDR_1_SIZE + \ FIELD_OFFSET(TA_ADDRESS, Address) + sizeof(TDI_ADDRESS_IP) // New debug locks [ShreeM] // This will enable us to figure out who took the lock last // and who released it last. New structure defined below and // lock_acquire and lock_release macros are redefined later. typedef struct _GPC_LOCK { NDIS_SPIN_LOCK Lock; #if DBG PETHREAD CurrentThread; KIRQL CurrentIRQL; LONG LockAcquired; // is it current held? UCHAR LastAcquireFile[8]; ULONG LastAcquireLine; UCHAR LastReleaseFile[8]; ULONG LastReleaseLine; #endif } GPC_LOCK, PGPC_LOCK; // // // states for blobs, patterns and more // typedef enum { GPC_STATE_READY = 0, GPC_STATE_INIT, GPC_STATE_ADD, GPC_STATE_MODIFY, GPC_STATE_REMOVE, GPC_STATE_FORCE_REMOVE, GPC_STATE_DELETE, GPC_STATE_INVALID, GPC_STATE_NOTREADY, GPC_STATE_ERROR, GPC_STATE_PENDING } GPC_STATE; // // ObjectVerification macro // #define VERIFY_OBJECT(_obj, _val) if(_obj) \ {if(*(GPC_ENUM_OBJECT_TYPE *)_obj!=_val) return STATUS_INVALID_HANDLE;} //Use this macro when you want to catch the error and not directly //return from the function #define VERIFY_OBJECT_WITH_STATUS(_obj, _val,__status) if(_obj) \ {if(*(GPC_ENUM_OBJECT_TYPE *)_obj!=_val) __status = STATUS_INVALID_HANDLE;} // // define event log error codes // #define GPC_ERROR_INIT_MAIN 0x00010000 #define GPC_ERROR_INIT_IOCTL 0x00020000 #define GPC_FLAGS_USERMODE_CLIENT 0x80000000 #define IS_USERMODE_CLIENT(_pc) \ TEST_BIT_ON((_pc)->Flags,GPC_FLAGS_USERMODE_CLIENT) #define IS_USERMODE_CLIENT_EX(_pc) \ TEST_BIT_ON((_pc)->Flags,GPC_FLAGS_USERMODE_CLIENT_EX) // // for ioctl // #define SHUTDOWN_DELETE_DEVICE 0x00000100 #define SHUTDOWN_DELETE_SYMLINK 0x00000200 // // helper macros // #define TEST_BIT_ON(_v,_b) (((_v)&(_b))==(_b)) #define TEST_BIT_OFF(_v,_b) (((_v)&(_b))==0) // // Define Default AutoPatternLimits // #define DEFAULT_SMALL_SYSTEM_AUTO_PATTERN_LIMIT 2000 #define DEFAULT_MEDIUM_SYSTEM_AUTO_PATTERN_LIMIT 8000 #define DEFAULT_LARGE_SYSTEM_AUTO_PATTERN_LIMIT 12000 // // Define Registry settings to read into // #define GPC_REG_KEY L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\GPC" // // Work Buffer size for reading from the registry // #define WORK_BUFFER_SIZE 256 // // Reg Key under which the limit on the number of autopatterns is stored // #define GPC_REG_AUTO_PATTERN_LIMIT L"AutoPatternLimit" #define GPC_AUTO_PATTERN_MIN 2000 #define GPC_AUTO_PATTERN_MAX 20000 #if DBG #define NDIS_INIT_LOCK(_sl) {\ NdisAllocateSpinLock(&(_sl)->Lock); \ TRACE(LOCKS,(_sl),(_sl)->Lock.OldIrql,"LOCK");\ (_sl)->LockAcquired = -1; \ strncpy((_sl)->LastAcquireFile, strrchr(__FILE__,'\\')+1, 7); \ (_sl)->LastAcquireLine = __LINE__; \ strncpy((_sl)->LastReleaseFile, strrchr(__FILE__,'\\')+1, 7); \ (_sl)->LastReleaseLine = __LINE__; \ (_sl)->CurrentIRQL = KeGetCurrentIrql(); \ (_sl)->CurrentThread = PsGetCurrentThread(); \ } #define NDIS_LOCK(_sl) {\ NdisAcquireSpinLock(&(_sl)->Lock);\ TRACE(LOCKS,(_sl),(_sl)->Lock.OldIrql,"LOCK");\ (_sl)->LockAcquired = TRUE; \ strncpy((_sl)->LastAcquireFile, strrchr(__FILE__,'\\')+1, 7); \ (_sl)->LastAcquireLine = __LINE__; \ (_sl)->CurrentIRQL = KeGetCurrentIrql(); \ (_sl)->CurrentThread = PsGetCurrentThread(); \ } #define NDIS_UNLOCK(_sl) {\ (_sl)->LockAcquired = FALSE; \ strncpy((_sl)->LastReleaseFile, strrchr(__FILE__,'\\')+1, 7); \ (_sl)->LastReleaseLine = __LINE__; \ TRACE(LOCKS,(_sl),(_sl)->Lock.OldIrql,"UNLOCK");\ NdisReleaseSpinLock(&(_sl)->Lock);\ } #define NDIS_DPR_LOCK(_sl) {\ NdisDprAcquireSpinLock(&(_sl)->Lock);\ TRACE(LOCKS,(_sl),(_sl)->Lock.OldIrql,"DPR_LOCK");\ (_sl)->LockAcquired = TRUE; \ strncpy((_sl)->LastAcquireFile, strrchr(__FILE__,'\\')+1, 7); \ (_sl)->LastAcquireLine = __LINE__; \ (_sl)->CurrentIRQL = KeGetCurrentIrql(); \ (_sl)->CurrentThread = PsGetCurrentThread(); \ } #define NDIS_DPR_UNLOCK(_sl) {\ (_sl)->LockAcquired = FALSE; \ strncpy((_sl)->LastReleaseFile, strrchr(__FILE__,'\\')+1, 7); \ (_sl)->LastReleaseLine = __LINE__; \ TRACE(LOCKS,(_sl),(_sl)->Lock.OldIrql,"DPR_UNLOCK");\ NdisDprReleaseSpinLock(&(_sl)->Lock);\ } #else #define NDIS_INIT_LOCK(_sl) NdisAllocateSpinLock(&(_sl)->Lock) #define NDIS_LOCK(_sl) NdisAcquireSpinLock(&(_sl)->Lock) #define NDIS_UNLOCK(_sl) NdisReleaseSpinLock(&(_sl)->Lock) #define NDIS_DPR_LOCK(_sl) NdisDprAcquireSpinLock(&(_sl)->Lock) #define NDIS_DPR_UNLOCK(_sl) NdisDprReleaseSpinLock(&(_sl)->Lock) #endif #if DBG && EXTRA_DBG #define VERIFY_LIST(_l) DbgVerifyList(_l) #else #define VERIFY_LIST(_l) #endif #define GpcRemoveEntryList(_pl) {PLIST_ENTRY _q = (_pl)->Flink;VERIFY_LIST(_pl);RemoveEntryList(_pl);InitializeListHead(_pl);VERIFY_LIST(_q);} #define GpcInsertTailList(_l,_e) VERIFY_LIST(_l);InsertTailList(_l,_e);VERIFY_LIST(_e) #define GpcInsertHeadList(_l,_e) VERIFY_LIST(_l);InsertHeadList(_l,_e);VERIFY_LIST(_e) #if 0 #define GpcInterlockedInsertTailList(_l,_e,_s) \ NdisInterlockedInsertTailList(_l,_e,_s) #else #define GpcInterlockedInsertTailList(_l,_e,_s) \ {NDIS_LOCK(_s);VERIFY_LIST(_l);InsertTailList(_l,_e);VERIFY_LIST(_l);NDIS_UNLOCK(_s);} #endif #if NEW_MRSW #define INIT_LOCK InitializeMRSWLock #define READ_LOCK EnterReader #define READ_UNLOCK ExitReader #define WRITE_LOCK EnterWriter #define WRITE_UNLOCK ExitWriter #else #define INIT_LOCK InitializeMRSWLock #define READ_LOCK AcquireReadLock #define READ_UNLOCK ReleaseReadLock #define WRITE_LOCK AcquireWriteLock #define WRITE_UNLOCK ReleaseWriteLock #endif // // Get the CF index from the client block // #define GetCFIndexFromClient(_cl) (((PCLIENT_BLOCK)(_cl))->pCfBlock->AssignedIndex) // // Get the client index from the client block // #define GetClientIndexFromClient(_cl) (((PCLIENT_BLOCK)(_cl))->AssignedIndex) // // return the blob block pointer for the pattern: // for specific patterns - its the blob entry in the CB // for generic patterns - its the pBlobBlock // #define GetBlobFromPattern(_p,_i) (_p)->arpBlobBlock[_i] // // return the index bit to the ULONG // #define ReleaseClientIndex(_v,_i) _v&=~(1<<_i) // clear the bit // // statistics macros // #define StatInc(_m) (glStat._m)++ #define StatDec(_m) (glStat._m)-- #define CfStatInc(_cf,_m) (glStat.CfStat[_cf]._m)++ #define CfStatDec(_cf,_m) (glStat.CfStat[_cf]._m)-- #define ProtocolStatInc(_p,_m) (glStat.ProtocolStat[_p]._m)++ #define ProtocolStatDec(_p,_m) (glStat.ProtocolStat[_p]._m)-- /* ///////////////////////////////////////////////////////////////// // // typedef // ///////////////////////////////////////////////////////////////// */ // // completion opcodes // typedef enum { OP_ANY_CFINFO, OP_ADD_CFINFO, OP_MODIFY_CFINFO, OP_REMOVE_CFINFO } GPC_COMPLETION_OP; // // define object type enum for handle verification // typedef enum { GPC_ENUM_INVALID, GPC_ENUM_CLIENT_TYPE, GPC_ENUM_CFINFO_TYPE, GPC_ENUM_PATTERN_TYPE } GPC_ENUM_OBJECT_TYPE; typedef struct _CF_BLOCK CF_BLOCK; typedef struct _PATTERN_BLOCK PATTERN_BLOCK; // // A queued notification structure // typedef struct _QUEUED_NOTIFY { LIST_ENTRY Linkage; GPC_NOTIFY_REQUEST_RES NotifyRes; PFILE_OBJECT FileObject; } QUEUED_NOTIFY, *PQUEUED_NOTIFY; // // A queued completion structure // typedef struct _QUEUED_COMPLETION { GPC_COMPLETION_OP OpCode; // what completed GPC_HANDLE ClientHandle; GPC_HANDLE CfInfoHandle; GPC_STATUS Status; } QUEUED_COMPLETION, *PQUEUED_COMPLETION; // // A pending IRP structure // typedef struct _PENDING_IRP { LIST_ENTRY Linkage; PIRP Irp; PFILE_OBJECT FileObject; QUEUED_COMPLETION QComp; } PENDING_IRP, *PPENDING_IRP; #if NEW_MRSW // // Multiple Readers Single Write definitions // code has been taken from (tdi\tcpipmerge\ip\ipmlock.h) // typedef struct _MRSW_LOCK { KSPIN_LOCK rlReadLock; KSPIN_LOCK rlWriteLock; LONG lReaderCount; } MRSW_LOCK, *PMRSW_LOCK; #else // // Multiple Readers Single Write definitions // code has been taken from the filter driver project (routing\ip\fltrdrvr) // typedef struct _MRSW_LOCK { KSPIN_LOCK SpinLock; LONG ReaderCount; } MRSW_LOCK, *PMRSW_LOCK; #endif // // The generic pattern database struct // typedef struct _GENERIC_PATTERN_DB { MRSW_LOCK Lock; Rhizome *pRhizome; // pointer to a Rhizome } GENERIC_PATTERN_DB, *PGENERIC_PATTERN_DB; // // A client block is used to store specific client context // typedef struct _CLIENT_BLOCK { // // !!! MUST BE FIRST FIELD !!! // GPC_ENUM_OBJECT_TYPE ObjectType; LIST_ENTRY ClientLinkage; // client blocks list link LIST_ENTRY BlobList; // list of blobs of the client CF_BLOCK *pCfBlock; GPC_CLIENT_HANDLE ClientCtx; ULONG AssignedIndex; ULONG Flags; ULONG State; GPC_LOCK Lock; REF_CNT RefCount; PFILE_OBJECT pFileObject; // used for async completion GPC_HANDLE ClHandle; // handle returned to the client GPC_CLIENT_FUNC_LIST FuncList; } CLIENT_BLOCK, *PCLIENT_BLOCK; // // A blob (A.K.A CF_INFO) block holds a GPC header + client specific data // typedef struct _BLOB_BLOCK { // // !!! MUST BE FIRST FIELD !!! // GPC_ENUM_OBJECT_TYPE ObjectType; LIST_ENTRY ClientLinkage; // linked on the client LIST_ENTRY PatternList; // head of pattern linked list LIST_ENTRY CfLinkage; // blobs on the CF //PCLIENT_BLOCK pClientBlock; // pointer to installer REF_CNT RefCount; GPC_STATE State; ULONG Flags; GPC_CLIENT_HANDLE arClientCtx[MAX_CLIENTS_CTX_PER_BLOB]; ULONG ClientStatusCountDown; GPC_STATUS LastStatus; GPC_LOCK Lock; CTEBlockStruc WaitBlockAddFailed; PCLIENT_BLOCK arpClientStatus[MAX_CLIENTS_CTX_PER_BLOB]; ULONG ClientDataSize; PVOID pClientData; ULONG NewClientDataSize; PVOID pNewClientData; PCLIENT_BLOCK pOwnerClient; PCLIENT_BLOCK pCallingClient; PCLIENT_BLOCK pCallingClient2; HANDLE OwnerClientHandle; GPC_CLIENT_HANDLE OwnerClientCtx; GPC_HANDLE ClHandle; // handle returned to the client // New fields to keep track of the additional information // // Rules: // (1) FileObject is referenced if NOT NULL // (2) Pattern needs to be freed if NOT NULL; should be used for AddPattern // PFILE_OBJECT FileObject; PGPC_IP_PATTERN Pattern; // // // assume only one client can accept the flow // PCLIENT_BLOCK pNotifiedClient; GPC_CLIENT_HANDLE NotifiedClientCtx; #if NO_USER_PENDING CTEBlockStruc WaitBlock; #endif } BLOB_BLOCK, *PBLOB_BLOCK; // // The classification block is an array of blob pointers // typedef struct _CLASSIFICATION_BLOCK { REF_CNT RefCount; ULONG NumberOfElements; HFHandle ClassificationHandle; // how to get back to index tbl // must be last PBLOB_BLOCK arpBlobBlock[1]; } CLASSIFICATION_BLOCK, *PCLASSIFICATION_BLOCK; // // A pattern block holds specific data for the pattern // typedef struct _PATTERN_BLOCK { // // !!! MUST BE FIRST FIELD !!! // GPC_ENUM_OBJECT_TYPE ObjectType; GPC_STATE State; LIST_ENTRY BlobLinkage[GPC_CF_MAX]; // linked on the blob LIST_ENTRY TimerLinkage; PBLOB_BLOCK arpBlobBlock[GPC_CF_MAX]; PCLIENT_BLOCK pClientBlock; PCLIENT_BLOCK pAutoClient; PCLASSIFICATION_BLOCK pClassificationBlock; ULONG WheelIndex; REF_CNT RefCount; ULONG ClientRefCount; ULONG TimeToLive; // for internal patterns ULONG Flags; ULONG Priority; // for generic pattern PVOID DbCtx; GPC_LOCK Lock; GPC_HANDLE ClHandle; // handle returned to the client ULONG ProtocolTemplate; } PATTERN_BLOCK, *PPATTERN_BLOCK; // // A CF block struct. This would construct a linked list of Cf blocks. // typedef struct _CF_BLOCK { REF_CNT RefCount; LIST_ENTRY Linkage; // on the global list LIST_ENTRY ClientList; // for the client blocks LIST_ENTRY BlobList; // list of blobs ULONG NumberOfClients; ULONG AssignedIndex; ULONG ClientIndexes; GPC_LOCK Lock; //MRSW_LOCK ClientSync; GPC_LOCK ClientSync; ULONG MaxPriorities; PGENERIC_PATTERN_DB arpGenericDb[GPC_PROTOCOL_TEMPLATE_MAX]; } CF_BLOCK, *PCF_BLOCK; typedef struct _SPECIFIC_PATTERN_DB { MRSW_LOCK Lock; PatHashTable *pDb; } SPECIFIC_PATTERN_DB, *PSPECIFIC_PATTERN_DB; typedef struct _FRAGMENT_DB { MRSW_LOCK Lock; PatHashTable *pDb; } FRAGMENT_DB, *PFRAGMENT_DB; // // A context structure to pass to the pathash scan routine // typedef struct _SCAN_STRUCT { PCLIENT_BLOCK pClientBlock; PPATTERN_BLOCK pPatternBlock; PBLOB_BLOCK pBlobBlock; ULONG Priority; BOOLEAN bRemove; } SCAN_STRUCT, *PSCAN_STRUCT; // // A protocol block holds pointers to databases for a specific // protocol template // typedef struct _PROTOCOL_BLOCK { LIST_ENTRY TimerPatternList[NUMBER_OF_WHEELS]; ULONG CurrentWheelIndex; ULONG SpecificPatternCount; ULONG GenericPatternCount; ULONG AutoSpecificPatternCount; ULONG ProtocolTemplate; ULONG PatternSize; SPECIFIC_PATTERN_DB SpecificDb; PVOID pProtocolDb; // fragments GPC_LOCK PatternTimerLock[NUMBER_OF_WHEELS]; NDIS_TIMER PatternTimer; } PROTOCOL_BLOCK, *PPROTOCOL_BLOCK; // // Global data block // typedef struct _GLOBAL_BLOCK { LIST_ENTRY CfList; // CF list head LIST_ENTRY gRequestList; // Maintain a request list to deal with contention... GPC_LOCK Lock; GPC_LOCK RequestListLock; HandleFactory *pCHTable; // Hash table maps user mode handle to kmode pointer MRSW_LOCK ChLock; // lock for pCHTable PPROTOCOL_BLOCK pProtocols; // pointer to array of supported protocols MM_SYSTEMSIZE SystemSizeHint; ULONG AutoPatternLimit; } GLOBAL_BLOCK, *PGLOBAL_BLOCK; // // TCP Query Context . Allocated before calling TcpQueryInfo. // When calling TcpQueryInfo only pass Offset into this structure // pointing at RouteInfo. // into TCP. // Initialize the TcpPattern with remote address and remote port // before the call and check on call completion if the values are // of relevance : this will happen when protocol = UDP and stack // gives us only one IP address on TcpQueryInfo call completion // typedef struct _GPC_TCP_QUERY_CONTEXT { PGPC_IP_PATTERN pTcpPattern; PMDL pMdl; //This should be the last field //ROUTING_INFO_ADDR_1_SIZE //depends on that TDI_ROUTING_INFO RouteInfo; } GPC_TCP_QUERY_CONTEXT, *PGPC_TCP_QUERY_CONTEXT; // // New request block. This will be used to store the event and linkage. // Therefore, when a thread needs to block, allocate a request_block, allocate // an event, grab the requestlist lock , put this on the list and wait. // typedef struct _REQUEST_BLOCK { LIST_ENTRY Linkage; NDIS_EVENT RequestEvent; } REQUEST_BLOCK, *PREQUEST_BLOCK; #if NEW_MRSW // // VOID // InitRwLock( // PMRSW_LOCK pLock // ) // // Initializes the spin locks and the reader count // #define InitializeMRSWLock(l) { \ KeInitializeSpinLock(&((l)->rlReadLock)); \ KeInitializeSpinLock(&((l)->rlWriteLock)); \ (l)->lReaderCount = 0; \ } // // VOID // EnterReader( // PMRSW_LOCK pLock, // PKIRQL pCurrIrql // ) // // Acquires the Reader Spinlock (now thread is at DPC). // InterlockedIncrements the reader count (interlocked because the reader // lock is not taken when the count is decremented in ExitReader()) // If the thread is the first reader, also acquires the Writer Spinlock (at // DPC to be more efficient) to block writers // Releases the Reader Spinlock from DPC, so that it remains at DPC // for the duration of the lock being held // // If a writer is in the code, the first reader will wait on the Writer // Spinlock and all subsequent readers will wait on the Reader Spinlock // If a reader is in the code and is executing the EnterReader, then a new // reader will wait for sometime on the Reader Spinlock, and then proceed // on to the code (at DPC) // #define EnterReader(l, q) {\ KeAcquireSpinLock(&((l)->rlReadLock), (q)); \ TRACE(LOCKS,l,*q,"EnterReader"); \ if(InterlockedIncrement(&((l)->lReaderCount)) == 1) { \ TRACE(LOCKS,l,(l)->lReaderCount,"EnterReader1"); \ KeAcquireSpinLockAtDpcLevel(&((l)->rlWriteLock)); \ TRACE(LOCKS,l,(l)->rlWriteLock,"EnterReader2"); \ } \ TRACE(LOCKS,l,(l)->lReaderCount,"EnterReader3"); \ KeReleaseSpinLockFromDpcLevel(&((l)->rlReadLock)); \ } #define EnterReaderAtDpcLevel(l) {\ KeAcquireSpinLockAtDpcLevel(&((l)->rlReadLock)); \ if(InterlockedIncrement(&((l)->lReaderCount)) == 1) \ KeAcquireSpinLockAtDpcLevel(&((l)->rlWriteLock)); \ KeReleaseSpinLockFromDpcLevel(&((l)->rlReadLock)); \ } // // VOID // ExitReader( // PMRSW_LOCK pLock, // KIRQL kiOldIrql // ) // // InterlockedDec the reader count. // If this is the last reader, then release the Writer Spinlock to let // other writers in // Otherwise, just lower the irql to what was before the lock was // acquired. Either way, the irql is down to original irql // #define ExitReader(l, q) {\ TRACE(LOCKS,l,q,"ExitReader");\ if(InterlockedDecrement(&((l)->lReaderCount)) == 0) { \ TRACE(LOCKS,(l)->rlWriteLock,q,"ExitReader1"); \ KeReleaseSpinLock(&((l)->rlWriteLock), q); \ } \ else { \ TRACE(LOCKS,l,(l)->lReaderCount,"ExitReader2"); \ KeLowerIrql(q); \ } \ } #define ExitReaderFromDpcLevel(l) {\ if(InterlockedDecrement(&((l)->lReaderCount)) == 0) \ KeReleaseSpinLockFromDpcLevel(&((l)->rlWriteLock)); \ } // // EnterWriter( // PMRSW_LOCK pLock, // PKIRQL pCurrIrql // ) // // Acquire the reader and then the writer spin lock // If there are readers in the code, the first writer will wait // on the Writer Spinlock. All other writers will wait (with readers) // on the Reader Spinlock // If there is a writer in the code then a new writer will wait on // the Reader Spinlock #define EnterWriter(l, q) {\ KeAcquireSpinLock(&((l)->rlReadLock), (q)); \ TRACE(LOCKS,l,*q,"EnterWriter"); \ TRACE(LOCKS,l,(l)->rlWriteLock,"EnterWrite1"); \ KeAcquireSpinLockAtDpcLevel(&((l)->rlWriteLock)); \ } #define EnterWriterAtDpcLevel(l) { \ KeAcquireSpinLockAtDpcLevel(&((l)->rlReadLock)); \ KeAcquireSpinLockAtDpcLevel(&((l)->rlWriteLock)); \ } // // ExitWriter( // PMRSW_LOCK pLock, // KIRQL kiOldIrql // ) // // Release both the locks // #define ExitWriter(l, q) {\ TRACE(LOCKS,l,(l)->rlWriteLock,"ExitWrite1"); \ KeReleaseSpinLockFromDpcLevel(&((l)->rlWriteLock)); \ TRACE(LOCKS,l,q,"ExitWrite1"); \ KeReleaseSpinLock(&((l)->rlReadLock), q); \ } #define ExitWriterFromDpcLevel(l) {\ KeReleaseSpinLockFromDpcLevel(&((l)->rlWriteLock)); \ KeReleaseSpinLockFromDpcLevel(&((l)->rlReadLock)); \ } #else #define InitializeMRSWLock(_pLock) { \ (_pLock)->ReaderCount = 0; \ KeInitializeSpinLock(&((_pLock)->SpinLock)); \ } #define AcquireReadLock(_pLock,_pOldIrql) { \ TRACE(LOCKS, _pLock, (_pLock)->ReaderCount, "RL.1"); \ KeAcquireSpinLock(&((_pLock)->SpinLock),_pOldIrql); \ InterlockedIncrement(&((_pLock)->ReaderCount)); \ TRACE(LOCKS, _pLock, (_pLock)->ReaderCount, "RL.2"); \ KeReleaseSpinLockFromDpcLevel(&((_pLock)->SpinLock)); \ TRACE(LOCKS, _pLock, *(_pOldIrql), "RL.3"); \ } #define ReleaseReadLock(_pLock,_OldIrql) { \ TRACE(LOCKS, _pLock, (_pLock)->ReaderCount, "RU.1"); \ InterlockedDecrement(&((_pLock)->ReaderCount)); \ TRACE(LOCKS, _pLock, (_pLock)->ReaderCount, "RU.2"); \ KeLowerIrql(_OldIrql); \ TRACE(LOCKS, _pLock, _OldIrql, "RU.3"); \ } #define AcquireWriteLock(_pLock,_pOldIrql) { \ TRACE(LOCKS, _pLock, _pOldIrql, "WL.1"); \ KeAcquireSpinLock(&((_pLock)->SpinLock),_pOldIrql); \ TRACE(LOCKS, _pLock, (_pLock)->ReaderCount, "WL.2"); \ while(InterlockedDecrement(&((_pLock)->ReaderCount))>=0)\ { \ InterlockedIncrement (&((_pLock)->ReaderCount)); \ } \ TRACE(LOCKS, _pLock, (_pLock)->ReaderCount, "WL.3"); \ } #define ReleaseWriteLock(_pLock,_OldIrql) { \ TRACE(LOCKS, _pLock, (_pLock)->ReaderCount, "WU.1"); \ InterlockedExchange(&(_pLock)->ReaderCount,0); \ TRACE(LOCKS, _pLock, (_pLock)->ReaderCount, "WU.2"); \ KeReleaseSpinLock(&((_pLock)->SpinLock),_OldIrql); \ TRACE(LOCKS, _pLock, _OldIrql, "WU.3"); \ } #endif #if 1 #define RSC_READ_LOCK(_l,_i) NDIS_LOCK(_l) #define RSC_READ_UNLOCK(_l,_i) NDIS_UNLOCK(_l) #define RSC_WRITE_LOCK(_l,_i) NDIS_LOCK(_l) #define RSC_WRITE_UNLOCK(_l,_i) NDIS_UNLOCK(_l) #else #define RSC_READ_LOCK WRITE_LOCK #define RSC_READ_UNLOCK WRITE_UNLOCK #define RSC_WRITE_LOCK WRITE_LOCK #define RSC_WRITE_UNLOCK WRITE_UNLOCK #endif /* ///////////////////////////////////////////////////////////////// // // IP definitions // ///////////////////////////////////////////////////////////////// */ #define DEFAULT_VERLEN 0x45 // Default version and length. #define IP_VERSION 0x40 #define IP_VER_FLAG 0xF0 #define IP_RSVD_FLAG 0x0080 // Reserved. #define IP_DF_FLAG 0x0040 // 'Don't fragment' flag #define IP_MF_FLAG 0x0020 // 'More fragments flag' #define IP_OFFSET_MASK ~0x00E0 // Mask for extracting offset field. #if (defined(_M_IX86) && (_MSC_FULL_VER > 13009037)) || ((defined(_M_AMD64) || defined(_M_IA64)) && (_MSC_FULL_VER > 13009175)) #define net_short(_x) _byteswap_ushort((USHORT)(_x)) #define net_long(_x) _byteswap_ulong(_x) #else #define net_short(x) ((((x)&0xff) << 8) | (((x)&0xff00) >> 8)) #define net_long(x) (((((ulong)(x))&0xffL)<<24) | \ ((((ulong)(x))&0xff00L)<<8) | \ ((((ulong)(x))&0xff0000L)>>8) | \ ((((ulong)(x))&0xff000000L)>>24)) #endif /* * Protocols (from winsock.h) */ #define IPPROTO_IP 0 /* dummy for IP */ #define IPPROTO_ICMP 1 /* control message protocol */ #define IPPROTO_IGMP 2 /* group management protocol */ #define IPPROTO_GGP 3 /* gateway^2 (deprecated) */ #define IPPROTO_TCP 6 /* tcp */ #define IPPROTO_PUP 12 /* pup */ #define IPPROTO_UDP 17 /* user datagram protocol */ #define IPPROTO_IDP 22 /* xns idp */ #define IPPROTO_ND 77 /* UNOFFICIAL net disk proto */ #define IPPROTO_IPSEC 51 /* ???????? */ #define IPPROTO_RAW 255 /* raw IP packet */ #define IPPROTO_MAX 256 // // UDP header definition // typedef struct _UDP_HEADER { ushort uh_src; ushort uh_dest; ushort uh_length; ushort uh_xsum; } UDP_HEADER, *PUDP_HEADER; // //* IP Header format. // typedef struct _IP_HEADER { uchar iph_verlen; // Version and length. uchar iph_tos; // Type of service. ushort iph_length; // Total length of datagram. ushort iph_id; // Identification. ushort iph_offset; // Flags and fragment offset. uchar iph_ttl; // Time to live. uchar iph_protocol; // Protocol. ushort iph_xsum; // Header checksum. ULONG iph_src; // Source address. ULONG iph_dest; // Destination address. } IP_HEADER, *PIP_HEADER; // // Definition of the IPX header. // typedef struct _IPX_HEADER { USHORT CheckSum; UCHAR PacketLength[2]; UCHAR TransportControl; UCHAR PacketType; UCHAR DestinationNetwork[4]; UCHAR DestinationNode[6]; USHORT DestinationSocket; UCHAR SourceNetwork[4]; UCHAR SourceNode[6]; USHORT SourceSocket; } IPX_HEADER, *PIPX_HEADER; /* ///////////////////////////////////////////////////////////////// // // extern // ///////////////////////////////////////////////////////////////// */ extern GLOBAL_BLOCK glData; extern GPC_STAT glStat; #ifdef STANDALONE_DRIVER extern GPC_EXPORTED_CALLS glGpcExportedCalls; #endif // tags extern ULONG ClassificationFamilyTag; extern ULONG ClientTag; extern ULONG PatternTag; extern ULONG CfInfoTag; extern ULONG QueuedNotificationTag; extern ULONG PendingIrpTag; extern ULONG HandleFactoryTag; extern ULONG PathHashTag; extern ULONG RhizomeTag; extern ULONG GenPatternDbTag; extern ULONG FragmentDbTag; extern ULONG CfInfoDataTag; extern ULONG ClassificationBlockTag; extern ULONG ProtocolTag; extern ULONG DebugTag; extern ULONG TcpPatternTag; extern ULONG TcpQueryContextTag; // Lookaside lists extern NPAGED_LOOKASIDE_LIST ClassificationFamilyLL; extern NPAGED_LOOKASIDE_LIST ClientLL; extern NPAGED_LOOKASIDE_LIST PatternLL; //extern NPAGED_LOOKASIDE_LIST CfInfoLL; extern ULONG CfInfoLLSize; extern NPAGED_LOOKASIDE_LIST QueuedNotificationLL; extern NPAGED_LOOKASIDE_LIST PendingIrpLL; /* ///////////////////////////////////////////////////////////////// // // prototypes // ///////////////////////////////////////////////////////////////// */ NTSTATUS DriverEntry( IN PDRIVER_OBJECT DriverObject, IN PUNICODE_STRING RegistryPath ); GPC_STATUS InitSpecificPatternDb( IN PSPECIFIC_PATTERN_DB pDb, IN ULONG PatternSize ); GPC_STATUS UninitSpecificPatternDb( IN PSPECIFIC_PATTERN_DB pDb ); GPC_STATUS InitClassificationHandleTbl( IN HandleFactory **ppCHTable ); VOID UninitClassificationHandleTbl( IN HandleFactory *pCHTable ); GPC_STATUS InitializeGenericDb( IN PGENERIC_PATTERN_DB *ppGenericDb, IN ULONG NumEntries, IN ULONG PatternSize ); VOID UninitializeGenericDb( IN PGENERIC_PATTERN_DB *ppGenericDb, IN ULONG NumEntries ); PCLIENT_BLOCK CreateNewClientBlock(VOID); VOID ReleaseCfBlock( IN PCF_BLOCK pCf ); PCF_BLOCK CreateNewCfBlock( IN ULONG CfId, IN ULONG MaxPriorities ); VOID ReleaseClientBlock( IN PCLIENT_BLOCK pClientBlock ); PPATTERN_BLOCK CreateNewPatternBlock( IN ULONG Flags ); VOID ReleasePatternBlock( IN PPATTERN_BLOCK pPatternBlock ); PCLASSIFICATION_BLOCK CreateNewClassificationBlock( IN ULONG NumEntries ); ULONG AssignNewClientIndex( IN PCF_BLOCK pCfBlock ); GPC_STATUS AddGenericPattern( IN PCLIENT_BLOCK pClient, IN PUCHAR pPatternBits, IN PUCHAR pMaskBits, IN ULONG Priority, IN PBLOB_BLOCK pBlob, IN PPROTOCOL_BLOCK pProtocol, IN OUT PPATTERN_BLOCK *ppPattern ); GPC_STATUS AddSpecificPattern( IN PCLIENT_BLOCK pClient, IN PUCHAR pPatternBits, IN PUCHAR pMaskBits, IN PBLOB_BLOCK pBlob, IN PPROTOCOL_BLOCK pProtocol, IN OUT PPATTERN_BLOCK *ppPattern, OUT PCLASSIFICATION_HANDLE pCH ); ULONG GpcCalcHash( IN ULONG ProtocolTempId, IN PUCHAR pPattern ); VOID DereferencePattern( IN PPATTERN_BLOCK pPattern ); VOID DereferenceBlob( IN PBLOB_BLOCK pBlob ); PBLOB_BLOCK CreateNewBlobBlock( IN ULONG ClientDataSize, IN PVOID pClientData, BOOLEAN fChargeQuota ); VOID ReleaseBlobBlock( IN PBLOB_BLOCK pBlobBlock ); GPC_STATUS HandleFragment( IN PCLIENT_BLOCK pClientBlock, IN PPROTOCOL_BLOCK pProtocol, IN BOOLEAN bFirstFrag, IN BOOLEAN bLastFrag, IN ULONG PacketId, IN OUT PPATTERN_BLOCK *ppPatternBlock, OUT PBLOB_BLOCK *ppBlob ); NTSTATUS InternalSearchPattern( IN PCLIENT_BLOCK pClientBlock, IN PPROTOCOL_BLOCK pProtocol, IN PVOID pPatternKey, OUT PPATTERN_BLOCK *ppPatternBlock, OUT PCLASSIFICATION_HANDLE pClassificationHandle, IN BOOLEAN bNoCache ); GPC_STATUS InitFragmentDb( IN PFRAGMENT_DB *ppFragDb ); GPC_STATUS UninitFragmentDb( IN PFRAGMENT_DB pFragDb ); VOID DereferenceClient( IN PCLIENT_BLOCK pClient ); GPC_STATUS ClientAddCfInfo( IN PCLIENT_BLOCK pClient, IN PBLOB_BLOCK pBlob, OUT PGPC_CLIENT_HANDLE pClientCfInfoContext ); VOID ClientAddCfInfoComplete( IN PCLIENT_BLOCK pClient, IN PBLOB_BLOCK pBlob, IN GPC_STATUS Status ); GPC_STATUS ClientModifyCfInfo( IN PCLIENT_BLOCK pClient, IN PBLOB_BLOCK pBlob, IN ULONG CfInfoSize, IN PVOID pClientData ); VOID ClientModifyCfInfoComplete( IN PCLIENT_BLOCK pClient, IN PBLOB_BLOCK pBlob, IN GPC_STATUS Status ); GPC_STATUS ClientRemoveCfInfo( IN PCLIENT_BLOCK pClient, IN PBLOB_BLOCK pBlob, IN GPC_CLIENT_HANDLE ClientCfInfoContext ); VOID ClientRemoveCfInfoComplete( IN PCLIENT_BLOCK pClient, IN PBLOB_BLOCK pBlob, IN GPC_STATUS Status ); GPC_STATUS RemoveSpecificPattern( IN PCLIENT_BLOCK pClient, IN PPROTOCOL_BLOCK pProtocol, IN PPATTERN_BLOCK pPattern, IN BOOLEAN ForceRemoval, IN BOOLEAN DbLocked ); VOID ClientRefsExistForSpecificPattern( IN PCLIENT_BLOCK pClient, IN PPROTOCOL_BLOCK pProtocol, IN PPATTERN_BLOCK pPattern, IN BOOLEAN dbLocked ); VOID ReadySpecificPatternForDeletion( IN PCLIENT_BLOCK pClient, IN PPROTOCOL_BLOCK pProtocol, IN PPATTERN_BLOCK pPattern, IN BOOLEAN DbLocked ); GPC_STATUS RemoveGenericPattern( IN PCLIENT_BLOCK pClient, IN PPROTOCOL_BLOCK pProtocol, IN PPATTERN_BLOCK pPattern ); VOID ReleaseClassificationBlock( IN PCLASSIFICATION_BLOCK pClassificationBlock ); VOID ClearPatternLinks( IN PPATTERN_BLOCK pPattern, IN PPROTOCOL_BLOCK pProtocol, IN ULONG CfIndex ); VOID ModifyCompleteClients( IN PCLIENT_BLOCK pClient, IN PBLOB_BLOCK pBlob ); //CLASSIFICATION_HANDLE //GetClassificationHandle( // IN PCLIENT_BLOCK pClient, // IN PPATTERN_BLOCK pPattern // ); VOID FreeClassificationHandle( IN PCLIENT_BLOCK pClient, IN CLASSIFICATION_HANDLE CH ); GPC_STATUS CleanupBlobs( IN PCLIENT_BLOCK pClient ); VOID GpcReadRegistry(); NTSTATUS OpenRegKey( PHANDLE HandlePtr, PWCHAR KeyName ); NTSTATUS GetRegDWORDValue( HANDLE KeyHandle, PWCHAR ValueName, PULONG ValueData ); VOID GPC_REG_READ_DWORD( HANDLE hRegKey, PWCHAR pwcName, PULONG pulData, ULONG ulDefault, ULONG ulMax, ULONG ulMin); #ifdef STANDALONE_DRIVER /* ///////////////////////////////////////////////////////////////// // // GPC inetrface APIs // ///////////////////////////////////////////////////////////////// */ GPC_STATUS GpcGetCfInfoClientContext( IN GPC_HANDLE ClientHandle, IN CLASSIFICATION_HANDLE ClassificationHandle, OUT PGPC_CLIENT_HANDLE pClientCfInfoContext ); GPC_CLIENT_HANDLE GpcGetCfInfoClientContextWithRef( IN GPC_HANDLE ClientHandle, IN CLASSIFICATION_HANDLE ClassificationHandle, IN ULONG Offset ); GPC_STATUS GpcGetUlongFromCfInfo( IN GPC_HANDLE ClientHandle, IN CLASSIFICATION_HANDLE ClassificationHandle, IN ULONG Offset, IN PULONG pValue ); GPC_STATUS GpcRegisterClient( IN ULONG CfId, IN ULONG Flags, IN ULONG MaxPriorities, IN PGPC_CLIENT_FUNC_LIST pClientFuncList, IN GPC_CLIENT_HANDLE ClientContext, OUT PGPC_HANDLE pClientHandle ); GPC_STATUS GpcDeregisterClient( IN GPC_HANDLE ClientHandle ); GPC_STATUS GpcAddCfInfo( IN GPC_HANDLE ClientHandle, IN ULONG CfInfoSize, IN PVOID pClientCfInfo, IN GPC_CLIENT_HANDLE ClientCfInfoContext, OUT PGPC_HANDLE pGpcCfInfoHandle ); GPC_STATUS GpcAddPattern( IN GPC_HANDLE ClientHandle, IN ULONG ProtocolTemplate, IN PVOID Pattern, IN PVOID Mask, IN ULONG Priority, IN GPC_HANDLE GpcCfInfoHandle, OUT PGPC_HANDLE pGpcPatternHandle, OUT PCLASSIFICATION_HANDLE pClassificationHandle ); VOID GpcAddCfInfoNotifyComplete( IN GPC_HANDLE ClientHandle, IN GPC_HANDLE GpcCfInfoHandle, IN GPC_STATUS Status, IN GPC_CLIENT_HANDLE ClientCfInfoContext ); GPC_STATUS GpcModifyCfInfo ( IN GPC_HANDLE ClientHandle, IN GPC_HANDLE GpcCfInfoHandle, IN ULONG CfInfoSize, IN PVOID pClientCfInfo ); VOID GpcModifyCfInfoNotifyComplete( IN GPC_HANDLE ClientHandle, IN GPC_HANDLE GpcCfInfoHandle, IN GPC_STATUS Status ); GPC_STATUS GpcRemoveCfInfo ( IN GPC_HANDLE ClientHandle, IN GPC_HANDLE GpcCfInfoHandle ); VOID GpcRemoveCfInfoNotifyComplete( IN GPC_HANDLE ClientHandle, IN GPC_HANDLE GpcCfInfoHandle, IN GPC_STATUS Status ); GPC_STATUS GpcRemovePattern ( IN GPC_HANDLE ClientHandle, IN GPC_HANDLE GpcPatternHandle ); GPC_STATUS GpcClassifyPattern ( IN GPC_HANDLE ClientHandle, IN ULONG ProtocolTemplate, IN PVOID pPattern, OUT PGPC_CLIENT_HANDLE pClientCfInfoContext, IN OUT PCLASSIFICATION_HANDLE pClassificationHandle, IN ULONG Offset, IN PULONG pValue, IN BOOLEAN bNoCache ); GPC_STATUS GpcClassifyPacket ( IN GPC_HANDLE ClientHandle, IN ULONG ProtocolTemplate, IN PVOID pNdisPacket, IN ULONG TransportHeaderOffset, IN PTC_INTERFACE_ID InterfaceId, OUT PGPC_CLIENT_HANDLE pClientCfInfoContext, OUT PCLASSIFICATION_HANDLE pClassificationHandle ); GPC_STATUS GpcEnumCfInfo ( IN GPC_HANDLE ClientHandle, IN OUT PHANDLE pCfInfoHandle, OUT PHANDLE pCfInfoMapHandle, IN OUT PULONG pCfInfoCount, IN OUT PULONG pBufferSize, OUT PGPC_ENUM_CFINFO_BUFFER Buffer ); #endif // STANDALONE_DRIVER GPC_STATUS GetClientCtxAndUlongFromCfInfo( IN GPC_HANDLE ClientHandle, IN OUT PCLASSIFICATION_HANDLE pClassificationHandle, OUT PGPC_CLIENT_HANDLE pClientCfInfoContext, IN ULONG Offset, IN PULONG pValue ); GPC_STATUS privateGpcAddCfInfo( IN GPC_HANDLE ClientHandle, IN ULONG CfInfoSize, IN PVOID pClientCfInfoPtr, IN GPC_CLIENT_HANDLE ClientCfInfoContext, IN PFILE_OBJECT FileObject, IN PGPC_IP_PATTERN Pattern, OUT PGPC_HANDLE pGpcCfInfoHandle ); GPC_STATUS privateGpcRemoveCfInfo( IN GPC_HANDLE ClientHandle, IN GPC_HANDLE GpcCfInfoHandle, IN ULONG Flags ); GPC_STATUS privateGpcRemovePattern( IN GPC_HANDLE ClientHandle, IN GPC_HANDLE GpcPatternHandle, IN BOOLEAN ForceRemoval, IN BOOLEAN DbLocked ); VOID UMClientRemoveCfInfoNotify( IN PCLIENT_BLOCK pClient, IN PBLOB_BLOCK pBlob ); VOID UMCfInfoComplete( IN GPC_COMPLETION_OP OpCode, IN PCLIENT_BLOCK pClient, IN PBLOB_BLOCK pBlob, IN GPC_STATUS Status ); VOID CloseAllObjects( IN PFILE_OBJECT FileObject, IN PIRP Irp ); NTSTATUS IoctlInitialize( IN PDRIVER_OBJECT DriverObject, IN PULONG InitShutdownMask ); NTSTATUS CheckQueuedNotification( IN PIRP Irp, IN OUT ULONG *outputBufferLength ); NTSTATUS CheckQueuedCompletion( IN PQUEUED_COMPLETION pQItem, IN PIRP Irp ); VOID PatternTimerExpired( IN PVOID SystemSpecific1, IN PVOID FunctionContext, IN PVOID SystemSpecific2, IN PVOID SystemSpecific3 ); GPC_STATUS AddSpecificPatternWithTimer( IN PCLIENT_BLOCK pClient, IN ULONG ProtocolTemplate, IN PVOID PatternKey, OUT PPATTERN_BLOCK *ppPattern, OUT PCLASSIFICATION_HANDLE pClassificationHandle ); NTSTATUS InitPatternTimer( IN ULONG ProtocolTemplate ); #endif // __GPCDEF