windows-nt/Source/XPSP1/NT/net/qos/tc/dll/tckrnl.c
2020-09-26 16:20:57 +08:00

1498 lines
36 KiB
C

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
tckrnl.c
Abstract:
This module contains routines that talk to the kernel
Author:
Jim Stewart (jstew) August 14, 1996
Revision History:
Ofer Bar (oferbar) Oct 1, 1997
--*/
#include "precomp.h"
#pragma hdrstop
//
// we use this mutex to synchronous start up with other traffic.dll's
//
const UCHAR TrafficSyncMutex[] = "_TRAFFIC_CTL_MUTEX";
HANDLE hGpcNotifyThread = INVALID_HANDLE_VALUE;
HANDLE hGpcNotifyStopEvent = INVALID_HANDLE_VALUE;
DWORD
IoAddFlow(
IN PFLOW_STRUC pFlow,
IN BOOLEAN Async
)
/*++
Routine Description:
This procedure builds up the structure necessary to add a flow.
Arguments:
Return Value:
status
--*/
{
DWORD Status = NO_ERROR;
PCLIENT_STRUC pClient = pFlow->pInterface->pClient;
PTC_IFC pTcIfc = pFlow->pInterface->pTcIfc;
PCF_INFO_QOS Kflow;
PGPC_ADD_CF_INFO_REQ GpcReq;
PGPC_ADD_CF_INFO_RES GpcRes;
ULONG InBuffSize;
ULONG OutBuffSize;
ULONG CfInfoSize;
PIO_APC_ROUTINE pCbRoutine = NULL;
ULONG l;
HANDLE hEvent = NULL;
//
// allocate memory for a CF_INFO struct to be passed to the GPC.
//
ASSERT(pFlow->pGenFlow);
pFlow->GpcHandle = NULL;
l = pFlow->GenFlowLen;
ASSERT(l > 0);
CfInfoSize = l + FIELD_OFFSET(CF_INFO_QOS, GenFlow);
InBuffSize = sizeof(GPC_ADD_CF_INFO_REQ) + CfInfoSize;
//
// And for the return info...
//
OutBuffSize = sizeof(GPC_ADD_CF_INFO_RES);
AllocMem(&GpcRes, OutBuffSize);
pFlow->CompletionBuffer = (PVOID)GpcRes;
AllocMem(&GpcReq, InBuffSize);
if (GpcRes && GpcReq) {
RtlZeroMemory(GpcRes, OutBuffSize);
RtlZeroMemory(GpcReq, InBuffSize);
//
// fill in the flow information
//
GpcReq->ClientHandle = pFlow->pGpcClient->GpcHandle;
GpcReq->ClientCfInfoContext = pFlow;
GpcReq->CfInfoSize = CfInfoSize;
Kflow = (PCF_INFO_QOS)&GpcReq->CfInfo;
//
// fill the instance name
//
Kflow->InstanceNameLength = (USHORT) pTcIfc->InstanceNameLength;
RtlCopyMemory(Kflow->InstanceName,
pTcIfc->InstanceName,
pTcIfc->InstanceNameLength * sizeof(WCHAR));
//
// set the flow flags
//
Kflow->Flags = pFlow->UserFlags;
//
// copy the generic flow parameter
//
RtlCopyMemory(&Kflow->GenFlow,
pFlow->pGenFlow,
l);
if (pClient->ClHandlers.ClAddFlowCompleteHandler && Async) {
pCbRoutine = CbAddFlowComplete;
} else {
hEvent = pFlow->PendingEvent;
}
Status = DeviceControl( pGlobals->GpcFileHandle,
hEvent,
pCbRoutine,
(PVOID)pFlow,
&pFlow->IoStatBlock,
IOCTL_GPC_ADD_CF_INFO,
GpcReq,
InBuffSize,
GpcRes,
OutBuffSize);
if (!ERROR_FAILED(Status)) {
if (hEvent && Status == ERROR_SIGNAL_PENDING) {
//
// wait for the event to signal
//
IF_DEBUG(IOCTLS) {
WSPRINT(("IoAddFlow: Waiting for event 0x%X...\n",
PtrToUlong(hEvent)));
}
Status = WaitForSingleObject(hEvent,
INFINITE
);
IF_DEBUG(IOCTLS) {
WSPRINT(("IoAddFlow: ... Event 0x%X signaled, Status=0x%X\n",
PtrToUlong(hEvent), Status));
}
}
if (Status == NO_ERROR) {
Status = MapNtStatus2WinError(GpcRes->Status);
IF_DEBUG(IOCTLS) {
WSPRINT(("IoAddFlow: GpcRes returned=0x%X mapped to =0x%X\n",
GpcRes->Status, Status));
}
}
if (ERROR_SUCCESS == Status) {
ASSERT(GpcRes->GpcCfInfoHandle);
pFlow->GpcHandle = GpcRes->GpcCfInfoHandle;
pFlow->InstanceNameLength = GpcRes->InstanceNameLength;
RtlCopyMemory(pFlow->InstanceName,
GpcRes->InstanceName,
GpcRes->InstanceNameLength
);
pFlow->InstanceName[pFlow->InstanceNameLength/sizeof(WCHAR)] = L'\0';
IF_DEBUG(IOCTLS) {
WSPRINT(("IoAddFlow: Flow Handle=%d Name=%S\n",
pFlow->GpcHandle,
pFlow->InstanceName));
}
}
}
} else {
Status = ERROR_NOT_ENOUGH_MEMORY;
}
//
// No, it's not a bug
// GpcRes will be release in CompleteAddFlow
//
if (GpcReq)
FreeMem(GpcReq);
IF_DEBUG(IOCTLS) {
WSPRINT(("<==IoAddFlow: Status=0x%X\n",
Status));
}
return Status;
}
DWORD
IoAddClassMapFlow(
IN PFLOW_STRUC pFlow,
IN BOOLEAN Async
)
/*++
Routine Description:
This procedure builds up the structure necessary to add a flow.
Arguments:
Return Value:
status
--*/
{
DWORD Status = NO_ERROR;
PCLIENT_STRUC pClient = pFlow->pInterface->pClient;
PTC_IFC pTcIfc = pFlow->pInterface->pTcIfc;
PCF_INFO_CLASS_MAP Kflow;
PGPC_ADD_CF_INFO_REQ GpcReq;
PGPC_ADD_CF_INFO_RES GpcRes;
ULONG InBuffSize;
ULONG OutBuffSize;
ULONG CfInfoSize;
PIO_APC_ROUTINE pCbRoutine = NULL;
ULONG l;
HANDLE hEvent = NULL;
return ERROR_CALL_NOT_IMPLEMENTED;
#if NEVER
// As this is not published in MSDN and not implemented in PSCHED also
//
// allocate memory for a CF_INFO struct to be passed to the GPC.
//
ASSERT(pFlow->pClassMapFlow);
pFlow->GpcHandle = NULL;
l = sizeof(TC_CLASS_MAP_FLOW) + pFlow->pClassMapFlow->ObjectsLength;
CfInfoSize = l + FIELD_OFFSET(CF_INFO_CLASS_MAP, ClassMapInfo);
InBuffSize = sizeof(GPC_ADD_CF_INFO_REQ) + CfInfoSize;
//
// And for the return info...
//
OutBuffSize = sizeof(GPC_ADD_CF_INFO_RES);
AllocMem(&GpcRes, OutBuffSize);
pFlow->CompletionBuffer = (PVOID)GpcRes;
AllocMem(&GpcReq, InBuffSize);
if (GpcRes && GpcReq) {
RtlZeroMemory(GpcRes, OutBuffSize);
RtlZeroMemory(GpcReq, InBuffSize);
//
// fill in the flow information
//
GpcReq->ClientHandle = pFlow->pGpcClient->GpcHandle;
GpcReq->ClientCfInfoContext = pFlow;
GpcReq->CfInfoSize = CfInfoSize;
Kflow = (PCF_INFO_CLASS_MAP)&GpcReq->CfInfo;
//
// fill the instance name
//
Kflow->InstanceNameLength = (USHORT) pTcIfc->InstanceNameLength;
RtlCopyMemory(Kflow->InstanceName,
pTcIfc->InstanceName,
pTcIfc->InstanceNameLength * sizeof(WCHAR));
//
// copy the generic flow parameter
//
RtlCopyMemory(&Kflow->ClassMapInfo,
pFlow->pClassMapFlow,
l);
if (pClient->ClHandlers.ClAddFlowCompleteHandler && Async) {
pCbRoutine = CbAddFlowComplete;
} else {
hEvent = pFlow->PendingEvent;
}
Status = DeviceControl( pGlobals->GpcFileHandle,
hEvent,
pCbRoutine,
(PVOID)pFlow,
&pFlow->IoStatBlock,
IOCTL_GPC_ADD_CF_INFO,
GpcReq,
InBuffSize,
GpcRes,
OutBuffSize);
if (!ERROR_FAILED(Status)) {
if (hEvent && Status == ERROR_SIGNAL_PENDING) {
//
// wait for the event to signal
//
IF_DEBUG(IOCTLS) {
WSPRINT(("IoAddClassMapFlow: Waiting for event 0x%X...\n",
PtrToUlong(hEvent)));
}
Status = WaitForSingleObject(hEvent,
INFINITE
);
IF_DEBUG(IOCTLS) {
WSPRINT(("IoAddClassMapFlow: ... Event 0x%X signaled, Status=0x%X\n",
PtrToUlong(hEvent), Status));
}
}
if (Status == NO_ERROR) {
Status = MapNtStatus2WinError(GpcRes->Status);
IF_DEBUG(IOCTLS) {
WSPRINT(("IoAddFlow: GpcRes returned=0x%X mapped to =0x%X\n",
GpcRes->Status, Status));
}
}
if (!ERROR_FAILED(Status)) {
ASSERT(GpcRes->GpcCfInfoHandle);
pFlow->GpcHandle = GpcRes->GpcCfInfoHandle;
pFlow->InstanceNameLength = GpcRes->InstanceNameLength;
RtlCopyMemory(pFlow->InstanceName,
GpcRes->InstanceName,
GpcRes->InstanceNameLength
);
pFlow->InstanceName[pFlow->InstanceNameLength/sizeof(WCHAR)] = L'\0';
IF_DEBUG(IOCTLS) {
WSPRINT(("IoAddClassMapFlow: Flow Handle=%d Name=%S\n",
pFlow->GpcHandle,
pFlow->InstanceName));
}
}
}
} else {
Status = ERROR_NOT_ENOUGH_MEMORY;
}
//
// No, it's not a bug
// GpcRes will be release in CompleteAddFlow
//
if (GpcReq)
FreeMem(GpcReq);
IF_DEBUG(IOCTLS) {
WSPRINT(("<==IoAddClassMapFlow: Status=0x%X\n",
Status));
}
return Status;
#endif
}
DWORD
IoModifyFlow(
IN PFLOW_STRUC pFlow,
IN BOOLEAN Async
)
/*++
Routine Description:
This procedure builds up the structure necessary to modify a flow.
Arguments:
pFlow
Return Value:
status
--*/
{
DWORD Status = NO_ERROR;
PCLIENT_STRUC pClient = pFlow->pInterface->pClient;
PTC_IFC pTcIfc = pFlow->pInterface->pTcIfc;
PCF_INFO_QOS Kflow;
PGPC_MODIFY_CF_INFO_REQ GpcReq;
PGPC_MODIFY_CF_INFO_RES GpcRes;
ULONG InBuffSize;
ULONG OutBuffSize;
ULONG CfInfoSize;
PIO_APC_ROUTINE pCbRoutine = NULL;
ULONG l;
HANDLE hEvent = NULL;
//
// allocate memory for a CF_INFO struct to be passed to the GPC.
//
ASSERT(pFlow->pGenFlow1);
l = pFlow->GenFlowLen1;
ASSERT(l > 0);
CfInfoSize = l + FIELD_OFFSET(CF_INFO_QOS, GenFlow);
InBuffSize = sizeof(GPC_MODIFY_CF_INFO_REQ) + CfInfoSize;
//
// And for the return info...
//
OutBuffSize = sizeof(GPC_MODIFY_CF_INFO_RES);
AllocMem(&GpcRes, OutBuffSize);
pFlow->CompletionBuffer = (PVOID)GpcRes;
AllocMem(&GpcReq, InBuffSize);
if (GpcRes && GpcReq) {
RtlZeroMemory(GpcRes, OutBuffSize);
RtlZeroMemory(GpcReq, InBuffSize);
//
// fill in the flow information
//
GpcReq->ClientHandle = pFlow->pGpcClient->GpcHandle;
GpcReq->GpcCfInfoHandle = pFlow->GpcHandle;
GpcReq->CfInfoSize = CfInfoSize;
Kflow = (PCF_INFO_QOS)&GpcReq->CfInfo;
//
// fill the instance name
//
Kflow->InstanceNameLength = (USHORT) pTcIfc->InstanceNameLength;
RtlCopyMemory(Kflow->InstanceName,
pTcIfc->InstanceName,
pTcIfc->InstanceNameLength * sizeof(WCHAR));
//
// copy the generic flow parameter
//
RtlCopyMemory(&Kflow->GenFlow,
pFlow->pGenFlow1,
l);
if (pClient->ClHandlers.ClModifyFlowCompleteHandler && Async) {
pCbRoutine = CbModifyFlowComplete;
} else {
hEvent = pFlow->PendingEvent;
}
Status = DeviceControl( pGlobals->GpcFileHandle,
hEvent,
pCbRoutine,
(PVOID)pFlow,
&pFlow->IoStatBlock,
IOCTL_GPC_MODIFY_CF_INFO,
GpcReq,
InBuffSize,
GpcRes,
OutBuffSize);
if (!ERROR_FAILED(Status)) {
if (hEvent && Status == ERROR_SIGNAL_PENDING) {
//
// wait for the event to signal
//
IF_DEBUG(IOCTLS) {
WSPRINT(("IoModifyFlow: Waiting for event 0x%X\n",
PtrToUlong(hEvent)));
}
Status = WaitForSingleObject(hEvent,
INFINITE
);
IF_DEBUG(IOCTLS) {
WSPRINT(("IoModifyFlow: ... Event 0x%X signaled, Status=0x%X\n",
PtrToUlong(hEvent), Status));
}
}
if (Status == NO_ERROR) {
Status = MapNtStatus2WinError(GpcRes->Status);
IF_DEBUG(IOCTLS) {
WSPRINT(("IoModifyFlow: GpcRes returned=0x%X mapped to =0x%X\n",
GpcRes->Status, Status));
}
}
} else{
Status = MapNtStatus2WinError(GpcRes->Status);
IF_DEBUG(IOCTLS) {
WSPRINT(("IoModifyFlow: GpcRes returned=0x%X mapped to =0x%X\n",
GpcRes->Status, Status));
}
}
} else {
Status = ERROR_NOT_ENOUGH_MEMORY;
}
//
// No, it's not a bug
// GpcRes will be release in CompleteModifyFlow
//
if (GpcReq)
FreeMem(GpcReq);
IF_DEBUG(IOCTLS) {
WSPRINT(("IoModifyFlow: Status=0x%X\n",
Status));
}
return Status;
}
DWORD
IoDeleteFlow(
IN PFLOW_STRUC pFlow,
IN BOOLEAN Async
)
/*++
Routine Description:
This procedure builds up the structure necessary to delete a flow.
It then calls a routine to pass this info to the GPC.
Arguments:
pFlow
Return Value:
status
--*/
{
DWORD Status;
ULONG InBuffSize;
ULONG OutBuffSize;
PGPC_REMOVE_CF_INFO_REQ GpcReq;
PGPC_REMOVE_CF_INFO_RES GpcRes;
PIO_APC_ROUTINE pCbRoutine = NULL;
PCLIENT_STRUC pClient = pFlow->pInterface->pClient;
HANDLE hEvent = NULL;
if (IS_REMOVED(pFlow->Flags)) {
//
// this flow has been already deleted in the kernel
// due to a flow close notification.
// no need to send IOTCL to GPC, just return OK
//
IF_DEBUG(IOCTLS) {
WSPRINT(("IoDeleteFlow: Flow has already been deleted=0x%X\n",
PtrToUlong(pFlow)));
}
return NO_ERROR;
}
//
// If we add this over here, then if WMI deletes the flow,
// the user mode call will just return above.
//
GetLock(pFlow->Lock);
pFlow->Flags |= TC_FLAGS_REMOVED;
FreeLock(pFlow->Lock);
//
// allocate memory for in and out buffers
//
InBuffSize = sizeof(GPC_REMOVE_CF_INFO_REQ);
OutBuffSize = sizeof(GPC_REMOVE_CF_INFO_RES);
AllocMem(&GpcRes, OutBuffSize);
pFlow->CompletionBuffer = (PVOID)GpcRes;
AllocMem(&GpcReq, InBuffSize);
if (GpcReq && GpcRes){
IF_DEBUG(IOCTLS) {
WSPRINT(("IoDeleteFlow: preparing to delete the flow=0x%X\n",
PtrToUlong(pFlow)));
}
GpcReq->ClientHandle = pFlow->pGpcClient->GpcHandle;
GpcReq->GpcCfInfoHandle = pFlow->GpcHandle;
if (pClient->ClHandlers.ClDeleteFlowCompleteHandler && Async) {
pCbRoutine = CbDeleteFlowComplete;
} else {
hEvent = pFlow->PendingEvent;
}
Status = DeviceControl( pGlobals->GpcFileHandle,
hEvent,
pCbRoutine,
(PVOID)pFlow,
&pFlow->IoStatBlock,
IOCTL_GPC_REMOVE_CF_INFO,
GpcReq,
InBuffSize,
GpcRes,
OutBuffSize);
if (!ERROR_FAILED(Status)) {
if (hEvent && Status == ERROR_SIGNAL_PENDING) {
//
// wait for the event to signal
//
IF_DEBUG(IOCTLS) {
WSPRINT(("IoDeleteFlow: Waiting for event 0x%X\n",
PtrToUlong(hEvent)));
}
Status = WaitForSingleObject(hEvent,
INFINITE
);
IF_DEBUG(IOCTLS) {
WSPRINT(("IoDeleteFlow: ... Event 0x%X signaled, Status=0x%X\n",
PtrToUlong(hEvent), Status));
}
}
if (Status == NO_ERROR) {
Status = MapNtStatus2WinError(GpcRes->Status);
IF_DEBUG(IOCTLS) {
WSPRINT(("IoDeleteFlow: Gpc returned=0x%X mapped to 0x%X\n",
GpcRes->Status, Status));
}
//
// If the deletion was unsuccessful, let's un-mark the REMOVED flag.
//
if (ERROR_FAILED(Status)) {
GetLock(pFlow->Lock);
pFlow->Flags &= ~TC_FLAGS_REMOVED;
FreeLock(pFlow->Lock);
}
}
}
} else {
Status = ERROR_NOT_ENOUGH_MEMORY;
}
//
// No, it's not a bug
// GpcRes will be release in CompleteDeleteFlow
//
if (GpcReq)
FreeMem(GpcReq);
IF_DEBUG(IOCTLS) {
WSPRINT(("<==IoDeleteFlow: Status=0x%X\n",
Status));
}
return Status;
}
DWORD
IoAddFilter(
IN PFILTER_STRUC pFilter
)
/*++
Routine Description:
This procedure builds up the structure necessary to add a filter.
It then calls a routine to pass this info to the GPC.
Arguments:
pFilter
Return Value:
status
--*/
{
DWORD Status;
PGPC_ADD_PATTERN_REQ GpcReq;
PGPC_ADD_PATTERN_RES GpcRes;
ULONG InBuffSize;
ULONG OutBuffSize;
PFLOW_STRUC pFlow = pFilter->pFlow;
PTC_GEN_FILTER pGpcFilter = pFilter->pGpcFilter;
PUCHAR p;
ULONG PatternSize;
IO_STATUS_BLOCK IoStatBlock;
pFilter->GpcHandle = NULL;
ASSERT(pGpcFilter);
ASSERT(pFlow);
PatternSize = pGpcFilter->PatternSize;
InBuffSize = sizeof(GPC_ADD_PATTERN_REQ) + 2*PatternSize;
OutBuffSize = sizeof(GPC_ADD_PATTERN_RES);
AllocMem(&GpcReq, InBuffSize);
AllocMem(&GpcRes, OutBuffSize);
if (GpcReq && GpcRes){
IF_DEBUG(IOCTLS) {
WSPRINT(("IoAddFilter: Filling request: size: in=%d, out=%d\n",
InBuffSize, OutBuffSize));
}
GpcReq->ClientHandle = pFlow->pGpcClient->GpcHandle;
GpcReq->GpcCfInfoHandle = pFlow->GpcHandle;
GpcReq->ClientPatternContext = (GPC_CLIENT_HANDLE)pFilter;
GpcReq->Priority = 0;
GpcReq->PatternSize = PatternSize;
GpcReq->ProtocolTemplate = pFilter->GpcProtocolTemplate;
//
// fill in the pattern
//
p = (PUCHAR)&GpcReq->PatternAndMask;
RtlCopyMemory(p, pGpcFilter->Pattern, PatternSize);
//
// fill in the mask
//
p += PatternSize;
RtlCopyMemory(p, pGpcFilter->Mask, PatternSize);
Status = DeviceControl( pGlobals->GpcFileHandle,
NULL,
NULL,
NULL,
&IoStatBlock,
IOCTL_GPC_ADD_PATTERN,
GpcReq,
InBuffSize,
GpcRes,
OutBuffSize);
if (!ERROR_FAILED(Status)) {
Status = MapNtStatus2WinError(GpcRes->Status);
IF_DEBUG(IOCTLS) {
WSPRINT(("IoAddFilter: GpcRes returned=0x%X mapped to =0x%X\n",
GpcRes->Status, Status));
}
//
// save the filter handle
//
if (!ERROR_FAILED(Status)) {
pFilter->GpcHandle = GpcRes->GpcPatternHandle;
} else {
IF_DEBUG(IOCTLS) {
WSPRINT(("IoAddFilter: GpcRes returned=0x%X mapped to =0x%X\n",
GpcRes->Status, Status));
}
IF_DEBUG(IOCTLS) {
WSPRINT(("Error - failed the addfilter call\n"));
}
//ASSERT(Status == ERROR_DUPLICATE_FILTER); removed for WAN - interface up down situation
}
}
} else {
Status = ERROR_NOT_ENOUGH_MEMORY;
IF_DEBUG(ERRORS) {
WSPRINT(("IoAddFilter: Error =0x%X\n",
Status));
}
}
if (GpcReq)
FreeMem(GpcReq);
if (GpcRes)
FreeMem(GpcRes);
IF_DEBUG(IOCTLS) {
WSPRINT(("<==IoAddFilter: Returned =0x%X\n",
Status));
}
return Status;
}
DWORD
IoDeleteFilter(
IN PFILTER_STRUC pFilter
)
/*++
Routine Description:
This procedure builds up the structure necessary to delete a filter.
It then calls a routine to pass this info to the GPC.
Arguments:
pFilter
Return Value:
status
--*/
{
DWORD Status;
ULONG InBuffSize;
ULONG OutBuffSize;
GPC_REMOVE_PATTERN_REQ GpcReq;
GPC_REMOVE_PATTERN_RES GpcRes;
IO_STATUS_BLOCK IoStatBlock;
//
// allocate memory for in and out buffers
//
if (IS_REMOVED(pFilter->Flags)) {
//
// this filter has been already deleted in the kernel
// due to a flow close notification.
// no need to send IOTCL to GPC, just return OK
//
IF_DEBUG(IOCTLS) {
WSPRINT(("IoDeleteFilter: Filter has already been deleted=0x%X\n",
PtrToUlong(pFilter)));
}
return NO_ERROR;
}
//
// If we add this over here, then if WMI deletes the Interface (and the
// flows/filters) the user mode call will just return above.
//
GetLock(pFilter->Lock);
pFilter->Flags |= TC_FLAGS_REMOVED;
FreeLock(pFilter->Lock);
InBuffSize = sizeof(GPC_REMOVE_PATTERN_REQ);
OutBuffSize = sizeof(GPC_REMOVE_PATTERN_RES);
GpcReq.ClientHandle = pFilter->pFlow->pGpcClient->GpcHandle;
GpcReq.GpcPatternHandle = pFilter->GpcHandle;
ASSERT(GpcReq.ClientHandle);
ASSERT(GpcReq.GpcPatternHandle);
Status = DeviceControl( pGlobals->GpcFileHandle,
NULL,
NULL,
NULL,
&IoStatBlock,
IOCTL_GPC_REMOVE_PATTERN,
&GpcReq,
InBuffSize,
&GpcRes,
OutBuffSize
);
if (!ERROR_FAILED(Status)) {
Status = MapNtStatus2WinError(GpcRes.Status);
IF_DEBUG(IOCTLS) {
WSPRINT(("IoDeleteFilter: GpcRes returned=0x%X mapped to =0x%X\n",
GpcRes.Status, Status));
}
//
// If the deletion was unsuccessful, let's un-mark the REMOVED flag.
//
if (ERROR_FAILED(Status)) {
GetLock(pFilter->Lock);
pFilter->Flags &= ~TC_FLAGS_REMOVED;
FreeLock(pFilter->Lock);
}
}
IF_DEBUG(IOCTLS) {
WSPRINT(("<==IoDeleteFilter: Status=0x%X\n",
Status));
}
return Status;
}
DWORD
IoRegisterClient(
IN PGPC_CLIENT pGpcClient
)
{
DWORD Status;
GPC_REGISTER_CLIENT_REQ GpcReq;
GPC_REGISTER_CLIENT_RES GpcRes;
ULONG InBuffSize;
ULONG OutBuffSize;
IO_STATUS_BLOCK IoStatBlock;
InBuffSize = sizeof(GPC_REGISTER_CLIENT_REQ);
OutBuffSize = sizeof(GPC_REGISTER_CLIENT_RES);
GpcReq.CfId = pGpcClient->CfInfoType;
GpcReq.Flags = GPC_FLAGS_FRAGMENT;
GpcReq.MaxPriorities = 1;
GpcReq.ClientContext =
(GPC_CLIENT_HANDLE)UlongToPtr(GetCurrentProcessId()); // process id
Status = DeviceControl( pGlobals->GpcFileHandle,
NULL,
NULL,
NULL,
&IoStatBlock,
IOCTL_GPC_REGISTER_CLIENT,
&GpcReq,
InBuffSize,
&GpcRes,
OutBuffSize );
if (!ERROR_FAILED(Status)) {
Status = MapNtStatus2WinError(GpcRes.Status);
pGpcClient->GpcHandle = GpcRes.ClientHandle;
IF_DEBUG(IOCTLS) {
WSPRINT(("IoRegisterClient: GpcRes returned=0x%X mapped to =0x%X\n",
GpcRes.Status, Status));
}
}
IF_DEBUG(IOCTLS) {
WSPRINT(("<==IoRegisterClient: Status=0x%X\n",
Status));
}
return Status;
}
DWORD
IoDeregisterClient(
IN PGPC_CLIENT pGpcClient
)
{
DWORD Status;
GPC_DEREGISTER_CLIENT_REQ GpcReq;
GPC_DEREGISTER_CLIENT_RES GpcRes;
ULONG InBuffSize;
ULONG OutBuffSize;
IO_STATUS_BLOCK IoStatBlock;
InBuffSize = sizeof(GPC_DEREGISTER_CLIENT_REQ);
OutBuffSize = sizeof(GPC_DEREGISTER_CLIENT_RES);
GpcReq.ClientHandle = pGpcClient->GpcHandle;
Status = DeviceControl( pGlobals->GpcFileHandle,
NULL,
NULL,
NULL,
&IoStatBlock,
IOCTL_GPC_DEREGISTER_CLIENT,
&GpcReq,
InBuffSize,
&GpcRes,
OutBuffSize
);
if (!ERROR_FAILED(Status)) {
Status = MapNtStatus2WinError(GpcRes.Status);
IF_DEBUG(IOCTLS) {
WSPRINT(("IoDeegisterClient: GpcRes returned=0x%X mapped to =0x%X\n",
GpcRes.Status, Status));
}
}
IF_DEBUG(IOCTLS) {
WSPRINT(("<==IoDeregisterClient: Status=0x%X\n",
Status));
}
return Status;
}
PGPC_NOTIFY_REQUEST_RES GpcResCb;
DWORD
IoRequestNotify(
VOID
//IN PGPC_CLIENT pGpcClient
)
/*
Description:
This routine sends a notification request buffer to the GPC.
The request will pend until the GPC notifies about a flow
being deleted. This will cause a callback to CbGpcNotifyRoutine.
*/
{
DWORD Status;
ULONG OutBuffSize;
//
// allocate memory for in and out buffers
//
OutBuffSize = sizeof(GPC_NOTIFY_REQUEST_RES);
AllocMem(&GpcResCb, OutBuffSize);
if (GpcResCb){
Status = DeviceControl( pGlobals->GpcFileHandle,
NULL,
CbGpcNotifyRoutine,
(PVOID)GpcResCb,
&GpcResCb->IoStatBlock,
IOCTL_GPC_NOTIFY_REQUEST,
NULL, //GpcReq,
0, //InBuffSize,
GpcResCb,
OutBuffSize);
if (ERROR_FAILED(Status)) {
FreeMem(GpcResCb);
GpcResCb = NULL;
}
else if ( ERROR_PENDING(Status) )
{
Status = NO_ERROR;
}
} else {
Status = ERROR_NOT_ENOUGH_MEMORY;
}
IF_DEBUG(IOCTLS) {
WSPRINT(("<==IoRequestNotify: Buffer=%p Status=0x%X\n",
GpcResCb, Status));
}
return Status;
}
VOID
CancelIoRequestNotify()
/*
Description:
This routine cancels the IRP in GPC and waits for the pending
IO to be cancelled. The callback routine set an event when
IO request is canclled and this routine waits for that event
before returning.
*/
{
// Non-zero value of GpcResCb indicates a pending IRP
if (GpcResCb)
{
GpcCancelEvent = CreateEvent (
NULL,
FALSE,
FALSE,
NULL );
if ( CancelIo ( pGlobals->GpcFileHandle ) )
{
if ( GpcCancelEvent )
{
WaitForSingleObjectEx(
GpcCancelEvent,
INFINITE,
TRUE );
CloseHandle ( GpcCancelEvent );
GpcCancelEvent = NULL;
}
else
{
IF_DEBUG(IOCTLS) {
WSPRINT((
"CancelIo: Status=0x%X\n",
GetLastError() ));
}
}
}
FreeMem(GpcResCb);
IF_DEBUG(IOCTLS)
{
WSPRINT(("<==CancelIoRequestNotify: Freed %p\n",
GpcResCb ));
}
}
return;
}
void
IncrementLibraryUsageCount(
HINSTANCE hinst,
int nCount)
/*
Utility routine to increment the ref count on
the TRAFFIC.DLL so that it will not get unloaded
before the GPCNotify thread gets a chance to run.
*/
{
TCHAR szModuleName[_MAX_PATH];
GetModuleFileName(hinst, szModuleName, _MAX_PATH);
while (nCount--)
LoadLibrary(szModuleName);
return;
}
DWORD
GpcNotifyThreadFunction ()
/*
This routine registers an IRP with GPC to listen for
FLOW close notifications and waits for the stop event.
When the event is signalled the IRP is canceled and this
thread exits.
Since the wait is done in an alertable state GPC callbacks
are executed in this thread itself.
*/
{
DWORD dwError;
dwError = IoRequestNotify();
WaitForSingleObjectEx(
hGpcNotifyStopEvent,
INFINITE,
TRUE );
CancelIoRequestNotify();
FreeLibraryAndExitThread(
hinstTrafficDll,
0 );
return 0;
}
DWORD
StartGpcNotifyThread()
/*
Description:
This routine starts a thread which queues an IRP for
GPC notifications.
*/
{
DWORD dwError = 0;
DWORD dwThreadId = 0;
// Increment the ref count on this DLL so it will not be unloaded
// before the GpcNotifyThreadFunction gets to run
IncrementLibraryUsageCount(
hinstTrafficDll,
1);
// Create the stop event for the thread to receive
// GPC flow close notifications
hGpcNotifyStopEvent = CreateEvent (
NULL,
FALSE,
FALSE,
NULL );
if ( !hGpcNotifyStopEvent )
{
dwError = GetLastError();
goto Error;
}
// Start the thread.
hGpcNotifyThread = CreateThread(
NULL,
0,
(LPTHREAD_START_ROUTINE )GpcNotifyThreadFunction,
NULL,
0,
&dwThreadId );
if ( !hGpcNotifyThread )
{
dwError = GetLastError();
goto Error;
}
// Not closing the thread handle as StopGpcNotifyThread
// routine will use this handle to wait for thread to
// terminate.
return 0;
Error:
if ( hGpcNotifyStopEvent )
{
CloseHandle ( hGpcNotifyStopEvent );
hGpcNotifyStopEvent = NULL;
}
if ( hGpcNotifyThread )
{
CloseHandle ( hGpcNotifyThread );
hGpcNotifyThread = NULL;
}
return dwError;
}
DWORD
StopGpcNotifyThread()
/*
Description:
Signal the GPC notification thread to stop
and wait it to stop.
*/
{
// If there was no thread created nothing more to do.
if ( hGpcNotifyThread )
{
// Tell GPC Notify thread to stop
SetEvent ( hGpcNotifyStopEvent );
// Wait for it to stop
WaitForSingleObject (
hGpcNotifyThread,
INFINITE );
CloseHandle( hGpcNotifyThread );
hGpcNotifyThread = NULL;
CloseHandle ( hGpcNotifyStopEvent );
hGpcNotifyStopEvent = NULL;
}
return 0;
}
DWORD
IoEnumerateFlows(
IN PGPC_CLIENT pGpcClient,
IN OUT PHANDLE pEnumHandle,
IN OUT PULONG pFlowCount,
IN OUT PULONG pBufSize,
OUT PGPC_ENUM_CFINFO_RES *ppBuffer
)
/*
Description:
This routine sends a notification request buffer to the GPC.
The request will pend until the GPC notifies about a flow
being deleted. This will cause a callback to CbGpcNotifyRoutine.
*/
{
DWORD Status;
ULONG InBuffSize;
ULONG OutBuffSize;
PGPC_ENUM_CFINFO_REQ GpcReq;
PGPC_ENUM_CFINFO_RES GpcRes;
IO_STATUS_BLOCK IoStatBlock;
//
// allocate memory for in and out buffers
//
InBuffSize = sizeof(GPC_ENUM_CFINFO_REQ);
OutBuffSize = *pBufSize + FIELD_OFFSET(GPC_ENUM_CFINFO_RES,EnumBuffer);
*ppBuffer = NULL;
AllocMem(&GpcRes, OutBuffSize);
AllocMem(&GpcReq, InBuffSize);
if (GpcReq && GpcRes) {
GpcReq->ClientHandle = pGpcClient->GpcHandle;
GpcReq->EnumHandle = *pEnumHandle;
GpcReq->CfInfoCount = *pFlowCount;
Status = DeviceControl( pGlobals->GpcFileHandle,
NULL,
NULL,
NULL,
&IoStatBlock,
IOCTL_GPC_ENUM_CFINFO,
GpcReq,
InBuffSize,
GpcRes,
OutBuffSize);
if (!ERROR_FAILED(Status)) {
Status = MapNtStatus2WinError(GpcRes->Status);
IF_DEBUG(IOCTLS) {
WSPRINT(("IoEnumerateFlows: GpcRes returned=0x%X mapped to =0x%X\n",
GpcRes->Status, Status));
}
if (!ERROR_FAILED(Status)) {
*pEnumHandle = GpcRes->EnumHandle;
*pFlowCount = GpcRes->TotalCfInfo;
*pBufSize = (ULONG)IoStatBlock.Information -
FIELD_OFFSET(GPC_ENUM_CFINFO_RES,EnumBuffer);
*ppBuffer = GpcRes;
}
}
} else {
Status = ERROR_NOT_ENOUGH_MEMORY;
}
if (GpcReq)
FreeMem(GpcReq);
if (ERROR_FAILED(Status)) {
//
// free GpcReq only if there was an error
//
if (GpcRes)
FreeMem(GpcRes);
}
IF_DEBUG(IOCTLS) {
WSPRINT(("<==IoEnumerateFlows: Status=0x%X\n",
Status));
}
return Status;
}