Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1597 lines
42 KiB

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