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

3889 lines
96 KiB
C

/*++
Copyright (c) 1996 Microsoft Corporation
Module Name:
api.c
Abstract:
This module contains the traffic control apis.
Author:
Jim Stewart ( jstew ) July 28, 1996
Revision History:
Ofer Bar ( oferbar ) Oct 1, 1997 - Rev 2
Shreedhar Madhavapeddi (ShreeM) March 10, 1999 Rev 3
--*/
/*
*********************************************************************
Revision 3 => Changes [ShreeM]
1. Build concrete state machines for Interface, Flow and Filter structures.
2. Define Locks for each of these structures.
3. Use above Locks for recording every state transistion.
4. Use debug logs to record transitions.
5. The Global lock is always taken before any of the Flow, Filter or Interface locks.
*/
#include "precomp.h"
//#pragma hdrstop
//#include "oscode.h"
/*
************************************************************************
Description:
This will create a new client handle and will also associate
it with a client's handler list. It also checks for the version number.
Arguments:
TciVersion - The client expected version
ClientHandlerList - The client's handler list
pClientHandle - output client handle
Return Value:
NO_ERROR
ERROR_NOT_ENOUGH_MEMORY out of memory
ERROR_INVALID_PARAMETER one of the parameters is NULL
ERROR_INCOMPATIBLE_TC_VERSION wrong version
ERROR_NO_SYSTEM_RESOURCES not enough resources (handles)
************************************************************************
*/
DWORD
APIENTRY
TcRegisterClient(
IN ULONG TciVersion,
IN HANDLE ClRegCtx,
IN PTCI_CLIENT_FUNC_LIST ClientHandlerList,
OUT PHANDLE pClientHandle
)
{
DWORD Status;
PCLIENT_STRUC pClient;
BOOL RegisterWithGpc = FALSE;
VERIFY_INITIALIZATION_STATUS;
IF_DEBUG(CALLS) {
WSPRINT(("==>TcRegisterClient: Called: Ver= %d, Ctx=%x\n",
TciVersion, ClRegCtx));
}
if (IsBadWritePtr(pClientHandle,sizeof(HANDLE))) {
Status = ERROR_INVALID_PARAMETER;
IF_DEBUG(ERRORS) {
WSPRINT(("TcRegisterClient: Error = 0x%X\n", Status ));
}
return Status;
}
//
// Set a default pClientHandle as early as possible
//
__try {
*pClientHandle = TC_INVALID_HANDLE;
} __except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
IF_DEBUG(ERRORS) {
WSPRINT(("TcRegisterClient: Exception Error: = 0x%X\n", Status ));
}
return Status;
}
if (TciVersion != CURRENT_TCI_VERSION) {
Status = ERROR_INCOMPATIBLE_TCI_VERSION;
IF_DEBUG(ERRORS) {
WSPRINT(("TcRegisterClient: Error = 0x%X\n", Status ));
}
return Status;
}
if (IsBadReadPtr(ClientHandlerList,sizeof(TCI_CLIENT_FUNC_LIST))) {
Status = ERROR_INVALID_PARAMETER;
IF_DEBUG(ERRORS) {
WSPRINT(("TcRegisterClient: Error = 0x%X\n", Status ));
}
return Status;
}
if (IsBadCodePtr((FARPROC) ClientHandlerList->ClNotifyHandler)) {
//
// a client must support a notification handler
//
Status = ERROR_INVALID_PARAMETER;
IF_DEBUG(ERRORS) {
WSPRINT(("TcRegisterClient: Error = 0x%X\n", Status ));
}
return Status;
}
// Prevent another thread from doing TcRegisterClient and TcDeregisterClient
GetLock( ClientRegDeregLock );
//
// finish initialization (if needed)
//
InitializeWmi();
Status = EnumAllInterfaces();
if (ERROR_FAILED(Status)) {
FreeLock( ClientRegDeregLock );
return Status;
}
Status = OpenGpcClients(GPC_CF_QOS);
if (ERROR_FAILED(Status)) {
IF_DEBUG(ERRORS) {
WSPRINT(("TcRegisterClient: Error = 0x%X\n", Status ));
}
FreeLock( ClientRegDeregLock );
return Status;
}
OpenGpcClients(GPC_CF_CLASS_MAP);
//
// allocate a new client structure and link it on the global list
//
Status = CreateClientStruc(0, // This will be the client reg ctx
&pClient
);
if (ERROR_FAILED(Status)) {
IF_DEBUG(ERRORS) {
WSPRINT(("TcRegisterClient: Error = 0x%X\n", Status ));
}
FreeLock( ClientRegDeregLock );
return Status;
}
//
// copy the handler list privately
//
__try {
RtlCopyMemory(&pClient->ClHandlers,
ClientHandlerList,
sizeof(TCI_CLIENT_FUNC_LIST));
} __except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
IF_DEBUG(ERRORS) {
WSPRINT(("TcRegisterClient: Exception Error: = 0x%X\n", Status ));
}
FreeLock( ClientRegDeregLock );
return Status;
}
pClient->ClRegCtx = ClRegCtx;
//
// Update linked lists, add the client to the global linked list of
// clients.
//
// NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE! NOTE!
//
// Once we add the client to the list, it can get notified by an
// incoming event, for example: TC_NOTIFY_IFC_CHANGE,
// so everything should be in place by the time we release the lock!
//
GetLock(pClient->Lock);
SET_STATE(pClient->State, OPEN);
FreeLock(pClient->Lock);
GetLock( pGlobals->Lock );
// If this is the first client then register for GPC notifications
if ( IsListEmpty( &pGlobals->ClientList ) )
RegisterWithGpc = TRUE;
InsertTailList( &pGlobals->ClientList, &pClient->Linkage );
FreeLock( pGlobals->Lock );
//
// so far so good, set the returned handle
//
__try {
*pClientHandle = (HANDLE)pClient->ClHandle;
} __except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
IF_DEBUG(ERRORS) {
WSPRINT(("TcRegisterClient: Exception Error: = 0x%X\n", Status ));
}
// We couldn't return the handle so we do our best effort to undo
// the client registration
TcDeregisterClient((HANDLE)pClient->ClHandle);
FreeLock( ClientRegDeregLock );
return Status;
}
if ( RegisterWithGpc )
{
Status = StartGpcNotifyThread();
if ( Status )
{
// We couldn't return the handle so we do our best effort to undo
// the client registration
TcDeregisterClient((HANDLE)pClient->ClHandle);
FreeLock( ClientRegDeregLock );
return Status;
}
}
// Finally allow other TcRegisterClient and TcDeregisterClient to go through
FreeLock( ClientRegDeregLock );
IF_DEBUG(CALLS) {
WSPRINT(("<==TcRegisterClient: ClHandle=%d Status=%X\n",
pClient->ClHandle, Status));
}
return Status;
}
/*
************************************************************************
Description:
The will call the system to enumerate all the TC aware interfaces.
For each interface, it will return the interface instance name and
a list of supported network addresses. This list can also be empty
if the interface currently does not have an address associated with.
On return, *pBufferSize is set to the actual number of bytes filled
in Buffer. If the buffer is too small to hold all the interfaces
data, it will return ERROR_INSUFFICIENT_BUFFER.
Arguments:
ClientHandle - the client handle from TcRegisterClient
pBufferSize - in: allocate buffer size, out: returned byte count
InterfaceBuffer - the buffer
Return Value:
NO_ERROR
ERROR_INVALID_HANDLE invalid client handle
ERROR_INVALID_PARAMETER one of the parameters is NULL
ERROR_INSUFFICIENT_BUFFER buffer too small to enumerate all interfaces
ERROR_NOT_ENOUGH_MEMORY system out of memory
************************************************************************
*/
DWORD
APIENTRY
TcEnumerateInterfaces(
IN HANDLE ClientHandle,
IN OUT PULONG pBufferSize,
OUT PTC_IFC_DESCRIPTOR InterfaceBuffer
)
{
PCLIENT_STRUC pClient;
DWORD Status = NO_ERROR;
ULONG MyBufferSize = 2 KiloBytes; // is this enough?!?
ULONG Offset2IfcName;
ULONG Offset2IfcID;
INT t, InputBufSize, CurrentLength = 0;
PLIST_ENTRY pHead, pEntry;
PTC_IFC pTcIfc;
IF_DEBUG(CALLS) {
WSPRINT(("==>TcEnumerateInterfaces: Called: ClientHandle= %d",
ClientHandle ));
}
VERIFY_INITIALIZATION_STATUS;
if ( IsBadWritePtr(pBufferSize, sizeof(ULONG))
|| IsBadWritePtr(InterfaceBuffer, *pBufferSize) ) {
return ERROR_INVALID_PARAMETER;
}
__try {
InputBufSize = *pBufferSize;
*pBufferSize = 0; // reset it in case of an error
} __except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
return Status;
}
pClient = (PCLIENT_STRUC)GetHandleObjectWithRef(ClientHandle, ENUM_CLIENT_TYPE, 'TCEI');
if (pClient == NULL) {
return ERROR_INVALID_HANDLE;
}
ASSERT((HANDLE)pClient->ClHandle == ClientHandle);
GetLock(pGlobals->Lock);
//
// walk the list of TC interfaces
//
pHead = &pGlobals->TcIfcList;
pEntry = pHead->Flink;
while (pEntry != pHead) {
pTcIfc = (PTC_IFC)CONTAINING_RECORD(pEntry,
TC_IFC,
Linkage
);
//
// 273978 - if the interface is down - dont show it.
//
GetLock(pTcIfc->Lock);
if (QUERY_STATE(pTcIfc->State) != OPEN) {
FreeLock(pTcIfc->Lock);
pEntry = pEntry->Flink;
continue;
}
FreeLock(pTcIfc->Lock);
//
// calculate the offset to the interface name buffer data
//
Offset2IfcName = FIELD_OFFSET(TC_IFC_DESCRIPTOR, AddressListDesc) +
pTcIfc->AddrListBytesCount;
//
// calculate the offset to the interface ID buffer data
//
Offset2IfcID = Offset2IfcName +
pTcIfc->InstanceNameLength + sizeof(WCHAR);
//
// total descriptor length
//
t = Offset2IfcID
+ pTcIfc->InstanceIDLength + sizeof(WCHAR); // ID
t = MULTIPLE_OF_EIGHT(t);
if (t <= InputBufSize - CurrentLength) {
__try {
//
// enough space in the buffer
//
InterfaceBuffer->Length = t;
//
// update the interface name pointer, place it right after
// the address desc. buffer
//
InterfaceBuffer->pInterfaceName =
(LPWSTR)((PUCHAR)InterfaceBuffer + Offset2IfcName);
//
// update the interface ID ID pointer, place it right after
// the Interface Name string
//
InterfaceBuffer->pInterfaceID =
(LPWSTR)((PUCHAR)InterfaceBuffer + Offset2IfcID);
//
// copy the address list
//
RtlCopyMemory(&InterfaceBuffer->AddressListDesc,
pTcIfc->pAddressListDesc,
pTcIfc->AddrListBytesCount
);
//
// copy the interface name
//
RtlCopyMemory(InterfaceBuffer->pInterfaceName,
&pTcIfc->InstanceName[0],
pTcIfc->InstanceNameLength + sizeof(WCHAR)
);
//
// copy the interface ID
//
RtlCopyMemory(InterfaceBuffer->pInterfaceID,
&pTcIfc->InstanceID[0],
pTcIfc->InstanceIDLength + sizeof(WCHAR)
);
//
// update the output buffer size
//
CurrentLength += t;
//
// advance the interface buffer to the next free space
//
InterfaceBuffer =
(PTC_IFC_DESCRIPTOR)((PUCHAR)InterfaceBuffer + t);
} __except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
IF_DEBUG(ERRORS) {
WSPRINT(("TcEnumerateInterfaces: Exception Error: = 0x%X\n",
Status ));
}
break;
}
//
// get next entry in the linked list
//
pEntry = pEntry->Flink;
} else {
//
// buffer too small to contain data
// so lets just
//
CurrentLength += t;
//
// get next entry in the linked list
//
pEntry = pEntry->Flink;
Status = ERROR_INSUFFICIENT_BUFFER;
}
}
FreeLock(pGlobals->Lock);
REFDEL(&pClient->RefCount, 'TCEI');
__try {
*pBufferSize = CurrentLength;
} __except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
IF_DEBUG(ERRORS) {
WSPRINT(("TcEnumerateInterfaces: Exception Error: = 0x%X\n",
Status ));
}
}
IF_DEBUG(CALLS) {
WSPRINT(("<==TcEnumerateInterfaces: Returned= 0x%X\n", Status ));
}
return Status;
}
/*
************************************************************************
Description:
This routine will open an interface for the client.
It needs to know the interface name, as it was returned from
TcEnumerateInterfaces. The client is also expected to give a context
that will be passed to the client upon certains notifications.
Arguments:
InterfaceName - the intefrace name
ClientHandle - as returned from TcRegisterClient
ClIfcCtx - a client context for this specific interface
pIfcHandle - returned interface handle
Return Value:
NO_ERROR
ERROR_INVALID_PARAMETER one of the parameters is NULL
ERROR_NOT_ENOUGH_MEMORY system out of memory
ERROR_NOT_FOUND failed to find an interface with the name provided
************************************************************************
*/
DWORD
APIENTRY
TcOpenInterfaceW(
IN LPWSTR pInterfaceName,
IN HANDLE ClientHandle,
IN HANDLE ClIfcCtx,
OUT PHANDLE pIfcHandle
)
{
DWORD Status;
ULONG Instance;
PINTERFACE_STRUC pClInterface;
PCLIENT_STRUC pClient;
HANDLE Handle;
PTC_IFC pTcIfc;
VERIFY_INITIALIZATION_STATUS;
//
// Validate the pifcHandle
//
if (IsBadWritePtr(pIfcHandle, sizeof(HANDLE))) {
return ERROR_INVALID_PARAMETER;
}
// Set a return value early
__try {
*pIfcHandle = TC_INVALID_HANDLE;
} __except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
IF_DEBUG(ERRORS) {
WSPRINT(("TcOpenInterfaces: Exception Error: = 0x%X\n",
Status ));
}
return Status;
}
//
// Validate the pInterfaceName
//
if (IsBadStringPtrW(pInterfaceName,MAX_STRING_LENGTH)) {
return ERROR_INVALID_PARAMETER;
}
IF_DEBUG(CALLS) {
WSPRINT(("==>TcOpenInterface: Called: ClientHandle= %d, Name=%S\n",
ClientHandle, pInterfaceName));
}
pClient = (PCLIENT_STRUC)GetHandleObjectWithRef(ClientHandle, ENUM_CLIENT_TYPE, 'TCOI');
if (pClient == NULL) {
return ERROR_INVALID_HANDLE;
}
ASSERT((HANDLE)pClient->ClHandle == ClientHandle);
//
// verify that the interface name exist
//
pTcIfc = GetTcIfcWithRef(pInterfaceName, 'TCOI');
if (pTcIfc == NULL) {
REFDEL(&pClient->RefCount, 'TCOI');
return ERROR_NOT_FOUND;
}
//
// create a client interface structure
//
Status = CreateClInterfaceStruc(ClIfcCtx, &pClInterface);
if (ERROR_FAILED(Status)) {
REFDEL(&pClient->RefCount, 'TCOI');
REFDEL(&pTcIfc->RefCount, 'TCOI');
return Status;
} else {
REFADD(&pClInterface->RefCount, 'TCOI');
}
//
// set up the client interface structure and link it to the client data
//
pClInterface->pTcIfc = pTcIfc;
pClInterface->pClient = pClient;
GetLock(pClInterface->Lock);
SET_STATE(pClInterface->State, OPEN);
FreeLock(pClInterface->Lock);
GetLock(pGlobals->Lock);
//
// add the interface on the client's list
//
GetLock(pClient->Lock);
GetLock(pTcIfc->Lock);
if ( (QUERY_STATE(pClient->State) != OPEN)
|| (QUERY_STATE(pTcIfc->State) != OPEN) )
{
FreeLock(pTcIfc->Lock);
FreeLock(pClient->Lock);
FreeLock(pGlobals->Lock);
IF_DEBUG(CALLS) {
WSPRINT(("<==TcOpenInterface: IfcHandle=%d Status=%X\n",
pClInterface->ClHandle, Status));
}
//
// Ideally we need to dereference the Interface, we really
// need only a subset of the functions.
//
FreeHandle(pClInterface->ClHandle);
CloseHandle(pClInterface->IfcEvent);
FreeMem(pClInterface);
REFDEL(&pClient->RefCount, 'TCOI');
REFDEL(&pTcIfc->RefCount, 'TCOI');
return ERROR_NOT_FOUND;
}
__try {
// the handle is all the client wants.
*pIfcHandle = (HANDLE)pClInterface->ClHandle;
} __except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
IF_DEBUG(ERRORS) {
WSPRINT(("TcOpenInterfaceW: Exception Error: = 0x%X\n",
Status ));
}
REFDEL(&pClient->RefCount, 'TCOI');
REFDEL(&pTcIfc->RefCount, 'TCOI');
REFDEL(&pClInterface->RefCount, 'TCOI');
return Status;
}
InsertTailList( &pClient->InterfaceList, &pClInterface->Linkage );
//
// for every interface add one ref count
//
REFADD(&pClient->RefCount, 'CIFC');
REFADD(&pTcIfc->RefCount, 'CIFC');
pClient->InterfaceCount++;
//
// add the interface on the TC interface list for back reference
//
InsertTailList( &pTcIfc->ClIfcList, &pClInterface->NextIfc );
FreeLock(pTcIfc->Lock);
FreeLock(pClient->Lock);
FreeLock(pGlobals->Lock);
REFDEL(&pClient->RefCount, 'TCOI');
REFDEL(&pTcIfc->RefCount, 'TCOI');
REFDEL(&pClInterface->RefCount, 'TCOI');
IF_DEBUG(CALLS) {
WSPRINT(("<==TcOpenInterface: IfcHandle=%d Status=%X\n",
pClInterface->ClHandle, Status));
}
return Status;
}
/*
************************************************************************
Description:
The ANSI version of TcOpenInterfaceW
Arguments:
See TcOpenInterfaceW
Return Value:
See TcOpenInterfaceW
************************************************************************
*/
DWORD
APIENTRY
TcOpenInterfaceA(
IN LPSTR pInterfaceName,
IN HANDLE ClientHandle,
IN HANDLE ClIfcCtx,
OUT PHANDLE pIfcHandle
)
{
LPWSTR pWstr;
int l;
DWORD Status;
if (IsBadWritePtr(pIfcHandle,sizeof(HANDLE))) {
return ERROR_INVALID_PARAMETER;
}
__try {
*pIfcHandle = TC_INVALID_HANDLE;
} __except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
IF_DEBUG(ERRORS) {
WSPRINT(("TcOpenInterfaceA: Exception Error: = 0x%X\n",
Status ));
}
return Status;
}
if (IsBadStringPtrA(pInterfaceName,MAX_STRING_LENGTH)) {
return ERROR_INVALID_PARAMETER;
}
__try {
l = strlen(pInterfaceName) + 1;
AllocMem(&pWstr, l*sizeof(WCHAR));
if (pWstr == NULL) {
return ERROR_NOT_ENOUGH_MEMORY;
}
if ( -1 == mbstowcs(pWstr, pInterfaceName, l)) {
FreeMem(pWstr);
return ERROR_NO_UNICODE_TRANSLATION;
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
IF_DEBUG(ERRORS) {
WSPRINT(("TcOpenInterfaceA: Exception Error: = 0x%X\n",
Status ));
}
return Status;
}
Status = TcOpenInterfaceW(pWstr,
ClientHandle,
ClIfcCtx,
pIfcHandle
);
FreeMem(pWstr);
return Status;
}
/*
************************************************************************
Description:
This will close the interface previously open witt TcOpenInterface.
All flows should be deleted before calling it, o/w an error will be
returned. All notificaitons will stop being reported on this interface.
Arguments:
InterfaceHandle - the interface handle
Return Value:
NO_ERROR
ERROR_INVALID_HANDLE bad interface handle
ERROR_TC_SUPPORTED_OBJECTS_EXIST not all flows have been deleted for
this interface
************************************************************************
*/
DWORD
APIENTRY
TcCloseInterface(
IN HANDLE InterfaceHandle
)
{
DWORD Status = NO_ERROR;
PINTERFACE_STRUC pInterface;
HANDLE hWaitEvent;
PFLOW_STRUC pFlow;
PLIST_ENTRY pEntry;
VERIFY_INITIALIZATION_STATUS;
IF_DEBUG(CALLS) {
WSPRINT(("==>TcCloseInterface: Called: IfcHandle= %d\n",
InterfaceHandle));
}
pInterface = (PINTERFACE_STRUC)GetHandleObjectWithRef(InterfaceHandle,
ENUM_INTERFACE_TYPE, 'TCCI');
if (pInterface == NULL) {
IF_DEBUG(ERRORS) {
WSPRINT(("==>TcCloseInterface: ERROR_INVALID_HANDLE\n"));
}
//
// If the Interface State is FORCED_KERNELCLOSE, it means we need
// to hang out here until the callback (in cbinterfacenotifyclient is done).
//
GetLock( pGlobals->Lock );
pInterface = (PINTERFACE_STRUC)GetHandleObject(InterfaceHandle,
ENUM_INTERFACE_TYPE);
if (pInterface) {
if (pInterface->CallbackThreadId == GetCurrentThreadId()) {
// same thread - bail!
FreeLock(pGlobals->Lock);
} else {
GetLock(pInterface->Lock);
// This is the state before the callback, so we shall wait here.
if (QUERY_STATE(pInterface->State) == FORCED_KERNELCLOSE) {
REFADD(&pInterface->RefCount, 'TCCW');
FreeLock(pInterface->Lock);
pInterface->Flags |= TC_FLAGS_WAITING;
hWaitEvent = pInterface->IfcEvent;
IF_DEBUG(INTERFACES) {
WSPRINT(("<==TcCloseInterface: Premature Forced Kernel Close, waiting for the callbacks to complete\n"));
}
FreeLock(pGlobals->Lock);
REFDEL(&pInterface->RefCount, 'TCCW');
WaitForSingleObject(hWaitEvent, INFINITE);
CloseHandle(hWaitEvent);
} else {
FreeLock(pInterface->Lock);
FreeLock(pGlobals->Lock);
}
}
} else {
FreeLock(pGlobals->Lock);
}
return ERROR_INVALID_HANDLE;
}
ASSERT((HANDLE)pInterface->ClHandle == InterfaceHandle);
//
// release the ref count we added when we opened the interface
//
GetLock( pGlobals->Lock );
if (pInterface->FlowCount > 0) {
IF_DEBUG(ERRORS) {
WSPRINT(("<==TcCloseInterface: ERROR: there are still open flows on this interface!\n"));
}
#if DBG
pEntry = pInterface->FlowList.Flink;
while (pEntry != &pInterface->FlowList) {
pFlow = CONTAINING_RECORD(pEntry, FLOW_STRUC, Linkage);
IF_DEBUG(ERRORS) {
WSPRINT(("<==TcCloseInterface: Flow %x (handle %x) is open with RefCount:%d\n", pFlow, pFlow->ClHandle, pFlow->RefCount));
}
pEntry = pEntry->Flink;
}
#endif
FreeLock(pGlobals->Lock);
REFDEL(&pInterface->RefCount, 'TCCI');
Status = ERROR_TC_SUPPORTED_OBJECTS_EXIST;
return Status;
}
//
// OK, so we are taking it out for sure now.
//
GetLock(pInterface->Lock);
if (QUERY_STATE(pInterface->State) == OPEN) {
SET_STATE(pInterface->State, USERCLOSED_KERNELCLOSEPENDING);
FreeLock(pInterface->Lock);
} else if (QUERY_STATE(pInterface->State) == FORCED_KERNELCLOSE) {
//
// if the interface is going down, we are going to notify the
// client, make sure we wait here till the callbacks are done.
//
FreeLock(pInterface->Lock);
pInterface->Flags |= TC_FLAGS_WAITING;
hWaitEvent = pInterface->IfcEvent;
IF_DEBUG(INTERFACES) {
WSPRINT(("<==TcCloseInterface: Forced Kernel Close, waiting for the callbacks to complete\n"));
}
FreeLock(pGlobals->Lock);
REFDEL(&pInterface->RefCount, 'TCCI');
WaitForSingleObject(hWaitEvent, INFINITE);
CloseHandle(hWaitEvent);
return ERROR_INVALID_HANDLE;
} else {
//
// Is someone else (wmi) already taking it out.
//
FreeLock(pInterface->Lock);
FreeLock( pGlobals->Lock );
REFDEL(&pInterface->RefCount, 'TCCI');
return ERROR_INVALID_HANDLE;
}
FreeLock(pGlobals->Lock);
Status = CloseInterface(pInterface, FALSE);
IF_DEBUG(CALLS) {
WSPRINT(("<==TcCloseInterface: Status=%X\n",
Status));
}
//
// Shall we wait until the last interface goes away? (292120 D)
//
GetLock( pGlobals->Lock );
if (pInterface->CallbackThreadId != 0 ) {
//
// We are doing a notification, don't block (343058)
//
FreeLock(pGlobals->Lock);
REFDEL(&pInterface->RefCount, 'TCCI');
} else {
pInterface->Flags |= TC_FLAGS_WAITING;
hWaitEvent = pInterface->IfcEvent;
IF_DEBUG(INTERFACES) {
WSPRINT(("<==TcCloseInterface: Waiting for event to get set when we are ready to delete!!\n"));
}
FreeLock(pGlobals->Lock);
REFDEL(&pInterface->RefCount, 'TCCI');
WaitForSingleObject(hWaitEvent, INFINITE);
CloseHandle(hWaitEvent);
}
return Status;
}
/*
************************************************************************
Description:
This call will add a new flow on the interface.
Arguments:
IfcHandle - the interface handle to add the flow on
ClFlowCtx - a client given flow context
AddressType - determines what protocol template to use with the GPC
Flags - reserved, will be used to indicate a persistent flow
pGenericFlow - flow parameters
pFlowHandle - returned flow handle in case of success
Return Value:
NO_ERROR
ERROR_SIGNAL_PENDING
General error codes:
ERROR_INVALID_HANDLE bad handle.
ERROR_NOT_ENOUGH_MEMORY system out of memory
ERROR_INVALID_PARAMETER a general parameter is invalid
TC specific error codes:
ERROR_INVALID_SERVICE_TYPE unspecified or bad intserv service type
ERROR_INVALID_TOKEN_RATE unspecified or bad TokenRate
ERROR_INVALID_PEAK_RATE bad PeakBandwidth
ERROR_INVALID_SD_MODE invalid ShapeDiscardMode
ERROR_INVALID_PRIORITY invalid priority value
ERROR_INVALID_TRAFFIC_CLASS invalid traffic class value
ERROR_ADDRESS_TYPE_NOT_SUPPORTED the address type is not supported for
this interface
ERROR_NO_SYSTEM_RESOURCES not enough resources to accommodate flows
************************************************************************
*/
DWORD
APIENTRY
TcAddFlow(
IN HANDLE IfcHandle,
IN HANDLE ClFlowCtx,
IN ULONG Flags,
IN PTC_GEN_FLOW pGenericFlow,
OUT PHANDLE pFlowHandle
)
{
DWORD Status, Status2 = NO_ERROR;
PFLOW_STRUC pFlow;
PINTERFACE_STRUC pInterface;
PCLIENT_STRUC pClient;
PGPC_CLIENT pGpcClient;
ULONG l;
HANDLE hFlowTemp;
IF_DEBUG(CALLS) {
WSPRINT(("==>TcAddFlow: Called: IfcHandle= %d, ClFlowCtx=%d\n",
IfcHandle, ClFlowCtx ));
}
VERIFY_INITIALIZATION_STATUS;
if (IsBadWritePtr(pFlowHandle,sizeof(HANDLE))) {
Status = ERROR_INVALID_PARAMETER;
IF_DEBUG(ERRORS) {
WSPRINT(("TcAddFlow: Error = 0x%X\n", Status ));
}
return Status;
}
__try {
*pFlowHandle = TC_INVALID_HANDLE;
if (IsBadReadPtr(pGenericFlow, sizeof(TC_GEN_FLOW))) {
Status = ERROR_INVALID_PARAMETER;
IF_DEBUG(ERRORS) {
WSPRINT(("TcAddFlow: Error = 0x%X\n", Status ));
}
return Status;
}
l = FIELD_OFFSET(TC_GEN_FLOW, TcObjects) + pGenericFlow->TcObjectsLength;
} __except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
IF_DEBUG(ERRORS) {
WSPRINT(("TcAddFlow: Exception Error: = 0x%X\n", Status ));
}
return Status;
}
if (IsBadReadPtr(pGenericFlow, l)) {
Status = ERROR_INVALID_PARAMETER;
IF_DEBUG(ERRORS) {
WSPRINT(("TcAddFlow: Error = 0x%X\n", Status ));
}
return Status;
}
pInterface = (PINTERFACE_STRUC)GetHandleObjectWithRef(IfcHandle,
ENUM_INTERFACE_TYPE, 'TCAF');
if (pInterface == NULL) {
Status = ERROR_INVALID_HANDLE;
IF_DEBUG(ERRORS) {
WSPRINT(("TcAddFlow: Error = 0x%X\n", Status ));
}
return Status;
}
ASSERT((HANDLE)pInterface->ClHandle == IfcHandle);
//
// search for an open GPC client that supports this address type
//
pGpcClient = FindGpcClient(GPC_CF_QOS);
if (pGpcClient == NULL) {
//
// not found!
//
Status = ERROR_ADDRESS_TYPE_NOT_SUPPORTED;
IF_DEBUG(ERRORS) {
WSPRINT(("TcAddFlow: Error = 0x%X\n", Status ));
}
REFDEL(&pInterface->RefCount, 'TCAF');
return Status;
}
//
// create a new flow structure
//
Status = CreateFlowStruc(ClFlowCtx, pGenericFlow, &pFlow);
if (ERROR_FAILED(Status)) {
IF_DEBUG(ERRORS) {
WSPRINT(("TcAddFlow: Error = 0x%X\n", Status ));
}
REFDEL(&pInterface->RefCount, 'TCAF');
return Status;
}
pClient = pInterface->pClient;
//
// initialize the flow structure and add it on the intefrace list
//
pFlow->pInterface = pInterface;
pFlow->UserFlags = Flags;
pFlow->pGpcClient = pGpcClient;
//
// call to actually add the flow
//
Status = IoAddFlow( pFlow, TRUE );
if (!ERROR_FAILED(Status)) {
__try {
*pFlowHandle = (HANDLE)pFlow->ClHandle;
} __except (EXCEPTION_EXECUTE_HANDLER) {
Status2 = GetExceptionCode();
IF_DEBUG(ERRORS) {
WSPRINT(("TcAddFlow: Exception Error: = 0x%X\n", Status2 ));
}
hFlowTemp = (HANDLE)pFlow->ClHandle;
}
}
if (!ERROR_PENDING(Status)) {
//
// call completed, either success or failure...
//
CompleteAddFlow(pFlow, Status);
}
//
// !!! don't reference pFlow after this since it may be gone!!!
//
if (Status2 != NO_ERROR) {
// We won't be able to return the flow, so we need to try to delete it
// and return the error
TcDeleteFlow(hFlowTemp);
return (Status2);
}
IF_DEBUG(CALLS) {
WSPRINT(("<==TcAddFlow: Returned= 0x%X\n", Status ));
}
return Status;
}
/*
************************************************************************
Description:
This call will modify the flow.
Arguments:
FlowHandle - flow handle to modify
pGenericFlow - new flow parameters
Return Value:
See TcAddFlow
************************************************************************
*/
DWORD
APIENTRY
TcModifyFlow(
IN HANDLE FlowHandle,
IN PTC_GEN_FLOW pGenericFlow
)
{
DWORD Status;
PFLOW_STRUC pFlow;
ULONG l;
IF_DEBUG(CALLS) {
WSPRINT(("==>TcModifyFlow: Called: FlowHandle= %d\n",
FlowHandle ));
}
VERIFY_INITIALIZATION_STATUS;
if (IsBadReadPtr(pGenericFlow,sizeof(TC_GEN_FLOW))) {
Status = ERROR_INVALID_PARAMETER;
IF_DEBUG(ERRORS) {
WSPRINT(("TcModifyFlow: Error = 0x%X\n", Status ));
}
return Status;
}
//
// Figure out the full length for immediate verification and also for later usage
//
__try {
l = FIELD_OFFSET(TC_GEN_FLOW, TcObjects) + pGenericFlow->TcObjectsLength;
} __except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
IF_DEBUG(ERRORS) {
WSPRINT(("TcModifyFlow: Exception Error: = 0x%X\n",
Status ));
}
return Status;
}
if (IsBadReadPtr(pGenericFlow,l)) {
Status = ERROR_INVALID_PARAMETER;
IF_DEBUG(ERRORS) {
WSPRINT(("TcModifyFlow: Error = 0x%X\n", Status ));
}
return Status;
}
pFlow = (PFLOW_STRUC)GetHandleObjectWithRef(FlowHandle, ENUM_GEN_FLOW_TYPE, 'TCMF');
if (pFlow == NULL) {
Status = ERROR_INVALID_HANDLE;
IF_DEBUG(ERRORS) {
WSPRINT(("TcModifyFlow: Error = 0x%X\n", Status ));
}
return Status;
}
else if (pFlow == INVALID_HANDLE_VALUE )
{
Status = ERROR_NOT_READY;
IF_DEBUG(ERRORS) {
WSPRINT(("TcModifyFlow: Error = 0x%X\n", Status ));
}
return Status;
}
ASSERT((HANDLE)pFlow->ClHandle == FlowHandle);
GetLock(pFlow->Lock);
if (IS_MODIFYING(pFlow->Flags)) {
FreeLock(pFlow->Lock);
IF_DEBUG(REFCOUNTS) {
WSPRINT(("0 DEREF FLOW %X (%X) - ref (%d)\n", pFlow->ClHandle, pFlow, pFlow->RefCount));
}
REFDEL(&pFlow->RefCount, 'TCMF');
return ERROR_NOT_READY;
}
AllocMem(&pFlow->pGenFlow1, l);
if (pFlow->pGenFlow1 == NULL) {
Status = ERROR_NOT_ENOUGH_MEMORY;
IF_DEBUG(ERRORS) {
WSPRINT(("TcModifyFlow: Error = 0x%X\n", Status ));
}
FreeLock(pFlow->Lock);
IF_DEBUG(REFCOUNTS) {
WSPRINT(("1 DEREF FLOW %X (%X) - ref (%d)\n", pFlow->ClHandle, pFlow, pFlow->RefCount));
}
REFDEL(&pFlow->RefCount, 'TCMF');
return Status;
}
__try {
RtlCopyMemory(pFlow->pGenFlow1, pGenericFlow, l);
} __except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
IF_DEBUG(ERRORS) {
WSPRINT(("TcModifyFlow: Exception Error: = 0x%X\n",
Status ));
}
FreeLock(pFlow->Lock);
//IF_DEBUG(REFCOUNTS) { WSPRINT(("2\n"));
IF_DEBUG(REFCOUNTS) {
WSPRINT(("2 DEREF FLOW %X (%X) ref (%d)\n", pFlow->ClHandle, pFlow, pFlow->RefCount));
}
REFDEL(&pFlow->RefCount, 'TCMF');
return Status;
}
pFlow->Flags |= TC_FLAGS_MODIFYING;
pFlow->GenFlowLen1 = l;
FreeLock(pFlow->Lock);
//
// call to actually modify the flow
//
Status = IoModifyFlow( pFlow, TRUE );
if (!ERROR_PENDING(Status)) {
//
// call completed, either success or failure...
//
CompleteModifyFlow(pFlow, Status);
}
//
// !!! don't reference pFlow after this since it may be gone!!!
//
//IF_DEBUG(REFCOUNTS) { WSPRINT(("3\n"));
IF_DEBUG(REFCOUNTS) {
WSPRINT(("3 DEREF FLOW %X (%X), ref(%d)\n", pFlow->ClHandle, pFlow, pFlow->RefCount));
}
IF_DEBUG(CALLS) {
WSPRINT(("<==TcModifyFlow: Returned= 0x%X\n", Status ));
}
return Status;
}
/*
************************************************************************
Description:
This will delete the flow. All the filters must have been deleted
by now, o/w an error code will be returned. Also the handle is
invalidated. No TC_NOTIFY_FLOW_CLOSE will be reported for this flow.
Arguments:
FlowHandle - handle of the flow to delete
Return Value:
NO_ERROR
ERROR_SIGNAL_PENDING
ERROR_INVALID_HANDLE invalid or NULL handle
ERROR_TC_SUPPORTED_OBJECTS_EXIST not all the filters have been deleted
************************************************************************
*/
DWORD
APIENTRY
TcDeleteFlow(
IN HANDLE FlowHandle
)
{
DWORD Status;
PFLOW_STRUC pFlow;
IF_DEBUG(CALLS) {
WSPRINT(("==>TcDeleteFlow: Called: FlowHandle= %d\n",
FlowHandle ));
}
VERIFY_INITIALIZATION_STATUS;
pFlow = (PFLOW_STRUC)GetHandleObjectWithRef(FlowHandle, ENUM_GEN_FLOW_TYPE, 'TCDF');
if (pFlow == NULL) {
Status = ERROR_INVALID_HANDLE;
IF_DEBUG(ERRORS) {
WSPRINT(("TcDeleteFlow: Error = 0x%X\n", Status ));
}
return Status;
}
else if (pFlow == INVALID_HANDLE_VALUE )
{
Status = ERROR_NOT_READY;
IF_DEBUG(ERRORS) {
WSPRINT(("TcDeleteFlow: Error = 0x%X\n", Status ));
}
return ERROR_NOT_READY;
}
ASSERT((HANDLE)pFlow->ClHandle == FlowHandle);
//
// Set the state and call to actually delete the flow
//
GetLock(pFlow->Lock);
if (QUERY_STATE(pFlow->State) == OPEN) {
if (IS_MODIFYING(pFlow->Flags))
{
//
// Someone else is taking this out.
//
FreeLock(pFlow->Lock);
REFDEL(&pFlow->RefCount, 'TCDF');
return ERROR_NOT_READY;
}
SET_STATE(pFlow->State, USERCLOSED_KERNELCLOSEPENDING);
FreeLock(pFlow->Lock);
} else {
//
// Someone else is taking this out.
//
FreeLock(pFlow->Lock);
REFDEL(&pFlow->RefCount, 'TCDF');
return ERROR_INVALID_HANDLE;
}
Status = DeleteFlow(pFlow, FALSE);
if (ERROR_FAILED(Status)) {
GetLock(pFlow->Lock);
SET_STATE(pFlow->State, OPEN);
FreeLock(pFlow->Lock);
}
//
// !!! don't reference pFlow after this since it may be gone!!!
//
//IF_DEBUG(REFCOUNTS) { WSPRINT(("4\n"));
IF_DEBUG(REFCOUNTS) {
WSPRINT(("4 DEREF FLOW %X (%X) ref(%d)\n", pFlow->ClHandle, pFlow, pFlow->RefCount));
}
REFDEL(&pFlow->RefCount, 'TCDF');
IF_DEBUG(CALLS) {
WSPRINT(("<==TcDeleteFlow: Returned= 0x%X\n", Status ));
}
return Status;
}
/*
************************************************************************
Description:
Will add a filter and attach it to the flow.
Arguments:
FlowHandle - handle of the flow to add the filter on
pGenericFilter - the filter characteristics
pFilterHandle - the returned filter handle after success
Return Value:
NO_ERROR
General error codes:
ERROR_INVALID_HANDLE bad handle.
ERROR_NOT_ENOUGH_MEMORY system out of memory
ERROR_INVALID_PARAMETER a general parameter is invalid
TC specific error codes:
ERROR_INVALID_ADDRESS_TYPE invalid address type
ERROR_DUPLICATE_FILTER attempt to install identical filters on
different flows
ERROR_FILTER_CONFLICT attempt to install conflicting filter
************************************************************************
*/
DWORD
APIENTRY
TcAddFilter(
IN HANDLE FlowHandle,
IN PTC_GEN_FILTER pGenericFilter,
OUT PHANDLE pFilterHandle
)
{
DWORD Status;
PFLOW_STRUC pFlow;
PFILTER_STRUC pFilter;
ULONG PatternSize;
IF_DEBUG(CALLS) {
WSPRINT(("==>TcAddFilter: Called: FlowHandle=%d\n", FlowHandle ));
}
VERIFY_INITIALIZATION_STATUS;
if (IsBadWritePtr(pFilterHandle,sizeof(HANDLE))) {
Status = ERROR_INVALID_PARAMETER;
IF_DEBUG(ERRORS) {
WSPRINT(("TcAddFilter: Error = 0x%X\n", Status ));
}
return Status;
}
__try {
*pFilterHandle = TC_INVALID_HANDLE;
if ( IsBadReadPtr(pGenericFilter,sizeof(TC_GEN_FILTER))
|| IsBadReadPtr(pGenericFilter->Pattern,pGenericFilter->PatternSize)
|| IsBadReadPtr(pGenericFilter->Mask,pGenericFilter->PatternSize)) {
Status = ERROR_INVALID_PARAMETER;
IF_DEBUG(ERRORS) {
WSPRINT(("TcAddFilter: Error = 0x%X\n", Status ));
}
return Status;
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
IF_DEBUG(ERRORS) {
WSPRINT(("TcAddFilter: Exception Error: = 0x%X\n", Status ));
}
return Status;
}
pFlow = (PFLOW_STRUC)GetHandleObjectWithRef(FlowHandle,
ENUM_GEN_FLOW_TYPE, 'TAFL');
if (pFlow == NULL) {
Status = ERROR_INVALID_HANDLE;
IF_DEBUG(ERRORS) {
WSPRINT(("TcAddFilter: Error = 0x%X\n", Status ));
}
return Status;
}
else if (pFlow == INVALID_HANDLE_VALUE )
{
Status = ERROR_NOT_READY;
IF_DEBUG(ERRORS) {
WSPRINT(("TcAddFilter: Error = 0x%X\n", Status ));
}
return Status;
}
ASSERT((HANDLE)pFlow->ClHandle == FlowHandle);
//
// create a new filter structure
//
Status = CreateFilterStruc(pGenericFilter, pFlow, &pFilter);
if ( Status != NO_ERROR ) {
if ( ERROR_PENDING(Status) )
Status = ERROR_NOT_READY;
IF_DEBUG(ERRORS) {
WSPRINT(("TcAddFilter: Error = 0x%X\n", Status ));
}
//IF_DEBUG(REFCOUNTS) { WSPRINT(("5\n"));
IF_DEBUG(REFCOUNTS) {
WSPRINT(("5 DEREF FLOW %X (%X) ref(%d)\n", pFlow->ClHandle, pFlow, pFlow->RefCount));
}
REFDEL(&pFlow->RefCount, 'TAFL');
return Status;
}
//
// initialize the filter structure and add it on the flow list
//
pFilter->pFlow = pFlow;
//
// call to actually add the filter
//
Status = IoAddFilter( pFilter );
if (!ERROR_FAILED(Status)) {
__try {
*pFilterHandle = (HANDLE)pFilter->ClHandle;
} __except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
IF_DEBUG(ERRORS) {
WSPRINT(("TcAddFilter: Exception Error: = 0x%X\n", Status ));
}
}
GetLock(pGlobals->Lock);
GetLock(pFlow->Lock);
if (QUERY_STATE(pFlow->State) == OPEN) {
SET_STATE(pFilter->State, OPEN);
InsertTailList(&pFlow->FilterList, &pFilter->Linkage);
REFADD(&pFlow->RefCount, 'FILT');
FreeLock(pFlow->Lock);
}
else {
IF_DEBUG(WARNINGS) {
WSPRINT(("Flow %X (handle %X) is not OPEN! \n", pFlow, pFlow->ClHandle));
}
FreeLock(pFlow->Lock);
DeleteFilter(pFilter);
Status = ERROR_INVALID_HANDLE;
}
FreeLock(pGlobals->Lock);
} else {
//
// failed, release the filter resources
//
REFDEL(&pFilter->RefCount, 'FILT');
}
//IF_DEBUG(REFCOUNTS) { WSPRINT(("6\n"));
IF_DEBUG(REFCOUNTS) {
WSPRINT(("6 DEREF FLOW %X (%X) (%d)\n", pFlow->ClHandle, pFlow, pFlow->RefCount));
}
REFDEL(&pFlow->RefCount, 'TAFL');
IF_DEBUG(CALLS) {
WSPRINT(("<==TcAddFilter: Returned= 0x%X\n", Status ));
}
return Status;
}
/*
************************************************************************
Description:
Deletes the filter and invalidates the handle.
Arguments:
FilterHandle - handle of the filter to be deleted
Return Value:
NO_ERROR
ERROR_INVALID_HANDLE invalid or NULL handle
************************************************************************
*/
DWORD
APIENTRY
TcDeleteFilter(
IN HANDLE FilterHandle
)
{
DWORD Status;
PFILTER_STRUC pFilter;
IF_DEBUG(CALLS) {
WSPRINT(("==>TcDeleteFilter: Called: FilterHandle=%d\n",
FilterHandle ));
}
VERIFY_INITIALIZATION_STATUS;
pFilter = (PFILTER_STRUC)GetHandleObjectWithRef(FilterHandle,
ENUM_FILTER_TYPE, 'TDFL');
if (pFilter == NULL) {
Status = ERROR_INVALID_HANDLE;
IF_DEBUG(ERRORS) {
WSPRINT(("TcDeleteFilter: Error = 0x%X\n", Status ));
}
return Status;
}
ASSERT((HANDLE)pFilter->ClHandle == FilterHandle);
GetLock(pFilter->Lock);
if (QUERY_STATE(pFilter->State) == OPEN) {
SET_STATE(pFilter->State, USERCLOSED_KERNELCLOSEPENDING);
FreeLock(pFilter->Lock);
} else {
//
// Someone else is taking this out.
//
FreeLock(pFilter->Lock);
REFDEL(&pFilter->RefCount, 'TDFL');
return ERROR_INVALID_HANDLE;
}
Status = DeleteFilter(pFilter);
IF_DEBUG(CALLS) {
WSPRINT(("<==TcDeleteFilter: Returned= 0x%X\n", Status ));
}
REFDEL(&pFilter->RefCount, 'TDFL');
return Status;
}
/*
************************************************************************
Description:
This will deregister the client and release all associated resources.
TC_NOTIFY_IFC_CHANGE notifications will no longer be reported to
this client. All interface must have being close prior to calling
this API, o/w an error will be returned.
Arguments:
ClientHandle - handle of the client to be deregistered
Return Value:
NO_ERROR
ERROR_INVALID_HANDLE invalid or NULL handle
ERROR_TC_SUPPORTED_OBJECTS_EXIST not all the interfaces have been
closed for this client
************************************************************************
*/
DWORD
TcDeregisterClient(
IN HANDLE ClientHandle
)
{
DWORD Status;
ULONG Instance;
PINTERFACE_STRUC pClInterface;
PCLIENT_STRUC pClient;
PLIST_ENTRY pEntry;
BOOLEAN fOpenInterfacesFound;
BOOLEAN fDeRegisterWithGpc = FALSE;
VERIFY_INITIALIZATION_STATUS;
Status = NO_ERROR;
fOpenInterfacesFound = FALSE;
IF_DEBUG(CALLS) {
WSPRINT(("==>TcDeregisterClient: ClientHandle=%d\n",
ClientHandle));
}
pClient = (PCLIENT_STRUC)GetHandleObject(ClientHandle, ENUM_CLIENT_TYPE);
if (pClient == NULL) {
IF_DEBUG(ERRORS) {
WSPRINT(("<==TcDeregisterClient: ERROR_INVALID_HANDLE\n"));
}
return ERROR_INVALID_HANDLE;
}
ASSERT((HANDLE)pClient->ClHandle == ClientHandle);
// Prevent another thread from doing TcRegisterClient and TcDeregisterClient
GetLock( ClientRegDeregLock );
GetLock( pGlobals->Lock );
// Go through the interface list and check if any interfaces are open.
// for a checked build, lets dump out the interfaces and the refcounts on these
// interfaces too. [ShreeM]
pEntry = pClient->InterfaceList.Flink;
while (pEntry != &pClient->InterfaceList) {
pClInterface = CONTAINING_RECORD(pEntry, INTERFACE_STRUC, Linkage);
GetLock(pClInterface->Lock);
if ((QUERY_STATE(pClInterface->State) == FORCED_KERNELCLOSE) ||
(QUERY_STATE(pClInterface->State) == KERNELCLOSED_USERCLEANUP)) {
#if DBG
IF_DEBUG(WARNINGS) {
WSPRINT(("<==TcDeregisterClient: Interface %x (H%x) is FORCED_KERNELCLOSE with RefCount:%d\n",
pClInterface, pClInterface->ClHandle, pClInterface->RefCount));
}
#endif
} else {
fOpenInterfacesFound = TRUE;
#if DBG
IF_DEBUG(ERRORS) {
WSPRINT(("<==TcDeregisterClient: Interface %x (H%x) is open with RefCount:%d\n", pClInterface, pClInterface->ClHandle, pClInterface->RefCount));
}
#endif
}
pEntry = pEntry->Flink;
FreeLock(pClInterface->Lock);
if (fOpenInterfacesFound) {
IF_DEBUG(ERRORS) {
WSPRINT(("<==TcDeregisterClient: ERROR_TC_SUPPORTED_OBJECTS_EXIST (%d Interfaces)\n", pClient->InterfaceCount));
}
FreeLock( ClientRegDeregLock );
FreeLock( pGlobals->Lock );
return ERROR_TC_SUPPORTED_OBJECTS_EXIST;
}
}
//
// Lets mark it as deleting.
//
GetLock(pClient->Lock);
SET_STATE(pClient->State, USERCLOSED_KERNELCLOSEPENDING);
FreeLock(pClient->Lock);
IF_DEBUG(HANDLES) {
WSPRINT(("<==TcDeregisterClient: client (%x), RefCount:%d\n", pClient->ClHandle, pClient->RefCount));
}
REFDEL(&pClient->RefCount, 'CLNT');
if ( IsListEmpty( &pGlobals->ClientList ) )
fDeRegisterWithGpc = TRUE;
FreeLock( pGlobals->Lock );
if ( fDeRegisterWithGpc )
{
// When there are no clients left stop listening to
// GPC notifications.
Status = StopGpcNotifyThread();
}
FreeLock( ClientRegDeregLock );
IF_DEBUG(CALLS) {
WSPRINT(("<==TcDeregisterClient: NO_ERROR\n" ));
}
return NO_ERROR;
}
/*
************************************************************************
Description:
Sends a WMI query on the guid with the instance name.
Also sets the notification state to TRUE (=notify) or FALSE (dont notify).
Arguments:
IfcHandle - interface to send the query to
pGuidParam - GUID of the queried property
NotifyChange - set the notification state for this property
BufferSize - size of allocated buffer
Buffer - the buffer for returned result
Return Value:
NO_ERROR
ERROR_INVALID_HANDLE bad interface handle
ERROR_INVALID_PARAMETER bad parameter
ERROR_INSUFFICIENT_BUFFER buffer too small for result
ERROR_NOT_SUPPORTED unsupported GUID
************************************************************************
*/
DWORD
APIENTRY
TcQueryInterface(
IN HANDLE IfcHandle,
IN LPGUID pGuidParam,
IN BOOLEAN NotifyChange,
IN OUT PULONG pBufferSize,
OUT PVOID Buffer
)
{
DWORD Status;
PINTERFACE_STRUC pInterface;
WMIHANDLE hWmiHandle;
TCHAR cstr[MAX_STRING_LENGTH];
PWNODE_SINGLE_INSTANCE pWnode;
ULONG cBufSize;
ULONG InputBufferSize;
IF_DEBUG(CALLS) {
WSPRINT(("==>TcQueryInterface: Called: Name=%d\n",
IfcHandle));
}
VERIFY_INITIALIZATION_STATUS;
if (IsBadWritePtr(pBufferSize, sizeof(ULONG))) {
return ERROR_INVALID_PARAMETER;
}
__try {
InputBufferSize = *pBufferSize;
*pBufferSize = 0;
} __except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
IF_DEBUG(ERRORS) {
WSPRINT(("TcModifyFlow: Exception Error: = 0x%X\n",
Status ));
}
return Status;
}
if (IsBadReadPtr(pGuidParam,sizeof(GUID))) {
return ERROR_INVALID_PARAMETER;
}
if ( (InputBufferSize != 0)
&& (IsBadWritePtr(Buffer,InputBufferSize)) )
{
return ERROR_INVALID_PARAMETER;
}
pInterface = (PINTERFACE_STRUC)GetHandleObjectWithRef(IfcHandle,
ENUM_INTERFACE_TYPE, 'TCQI');
if (pInterface == NULL) {
return ERROR_INVALID_HANDLE;
}
Status = WmiOpenBlock( pGuidParam, // object
0, // access
&hWmiHandle
);
if (ERROR_FAILED(Status)) {
TC_TRACE(ERRORS, ("[TcQueryInterface]: WmiOpenBlock failed with %x \n", Status));
REFDEL(&pInterface->RefCount, 'TCQI');
return Status;
}
//
// allocate memory for the output wnode
//
cBufSize = sizeof(WNODE_SINGLE_INSTANCE)
+ InputBufferSize
+ MAX_STRING_LENGTH * sizeof(TCHAR);
AllocMem(&pWnode, cBufSize);
if (pWnode == NULL) {
Status = ERROR_NOT_ENOUGH_MEMORY;
} else {
//
// query for the single instance
//
#ifndef UNICODE
if (-1 == wcstombs(cstr,
pInterface->pTcIfc->InstanceName,
pInterface->pTcIfc->InstanceNameLength
))
{
Status = ERROR_NO_UNICODE_TRANSLATION;
}
else
{
Status = WmiQuerySingleInstance( hWmiHandle,
cstr,
&cBufSize,
pWnode
);
}
#else
Status = WmiQuerySingleInstance( hWmiHandle,
pInterface->pTcIfc->InstanceName,
&cBufSize,
pWnode
);
#endif
if (!ERROR_FAILED(Status))
{
Status = WmiNotificationRegistration(pGuidParam,
NotifyChange,
CbWmiParamNotification,
PtrToUlong(IfcHandle),
NOTIFICATION_CALLBACK_DIRECT
);
if (Status == ERROR_WMI_ALREADY_DISABLED ||
Status == ERROR_WMI_ALREADY_ENABLED) {
//
// ignore these errors, we assumed it's okay
//
Status = NO_ERROR;
}
//
// Now that we are registered with WMI - add it OR delete it from our list. (258218)
//
if (NotifyChange) {
if (!TcipAddToNotificationList(
pGuidParam,
pInterface,
0
)) {
//
// Failed to put it on the list for some reason..
//
TC_TRACE(ERRORS, ("[TcQueryInterface]: Could not add the GUID/IFC to private list \n"));
}
} else {
if (!TcipDeleteFromNotificationList(
pGuidParam,
pInterface,
0
)) {
//
// Failed to remove it from the list for some reason..
//
TC_TRACE(ERRORS, ("[TcQueryInterface]: Could not remove the GUID/IFC from private list \n"));
}
}
}
if (!ERROR_FAILED(Status)) {
//
// parse the wnode
//
//
// check to see if the user allocated enough space for the
// returned buffer
//
if (pWnode->SizeDataBlock <= InputBufferSize) {
__try {
RtlCopyMemory(Buffer,
(PBYTE)OffsetToPtr(pWnode, pWnode->DataBlockOffset),
pWnode->SizeDataBlock
);
*pBufferSize = pWnode->SizeDataBlock;
} __except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
TC_TRACE(ERRORS, ("[TcQueryInterface]: Exception 0x%x while copying data \n", Status));
}
} else {
//
// output buffer too small
//
Status = ERROR_INSUFFICIENT_BUFFER;
__try {
*pBufferSize = pWnode->SizeDataBlock;
} __except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
}
}
}
}
WmiCloseBlock(hWmiHandle);
if (pWnode)
FreeMem(pWnode);
REFDEL(&pInterface->RefCount, 'TCQI');
IF_DEBUG(CALLS) {
WSPRINT(("<==TcQueryInterface: Returned= 0x%X\n", Status ));
}
return Status;
}
/*
************************************************************************
Description:
Sends a WMI set on the GUID with the instance name.
Not all propertied are writeable.
Arguments:
IfcHandle - interface handle to set the property on
pGuidParam - GUID of the property
BufferSize - allocate buffer size
Buffer - buffer that contains the data to be set
Return Value:
NO_ERROR
ERROR_INVALID_HANDLE bad interface handle
ERROR_INVALID_PARAMETER bad parameter
ERROR_NOT_SUPPORTED unsupported GUID
ERROR_WRITE_PROTECT GUID is read-only
************************************************************************
*/
DWORD
APIENTRY
TcSetInterface(
IN HANDLE IfcHandle,
IN LPGUID pGuidParam,
IN ULONG BufferSize,
IN PVOID Buffer
)
{
DWORD Status;
PINTERFACE_STRUC pInterface;
WMIHANDLE hWmiHandle;
TCHAR cstr[MAX_STRING_LENGTH];
PWNODE_SINGLE_INSTANCE pWnode;
ULONG cBufSize;
VERIFY_INITIALIZATION_STATUS;
if ( IsBadReadPtr(pGuidParam,sizeof(GUID))
|| (BufferSize == 0)
|| IsBadReadPtr(Buffer,BufferSize)) {
return ERROR_INVALID_PARAMETER;
}
pInterface = (PINTERFACE_STRUC)GetHandleObjectWithRef(IfcHandle,
ENUM_INTERFACE_TYPE, 'TCSI');
if (pInterface == NULL) {
return ERROR_INVALID_HANDLE;
}
__try {
Status = WmiOpenBlock( pGuidParam, // object
0, // access
&hWmiHandle
);
} __except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
IF_DEBUG(ERRORS) {
WSPRINT(("TcSetInterface: Exception Error: = 0x%X\n",
Status ));
}
REFDEL(&pInterface->RefCount, 'TCSI');
return Status;
}
if (ERROR_FAILED(Status)) {
TC_TRACE(ERRORS, ("[TcSetInterface]: WmiOpenBlock failed with error 0x%x \n", Status));
REFDEL(&pInterface->RefCount, 'TCSI');
return Status;
}
//
// allocate memory for the output wnode
//
cBufSize = sizeof(WNODE_SINGLE_INSTANCE)
+ BufferSize
+ MAX_STRING_LENGTH * sizeof(TCHAR);
AllocMem(&pWnode, cBufSize);
if (pWnode == NULL) {
Status = ERROR_NOT_ENOUGH_MEMORY;
} else {
//
// set the single instance
//
__try {
#ifndef UNICODE
if (-1 == wcstombs(cstr,
pInterface->pTcIfc->InstanceName,
pInterface->pTcIfc->InstanceNameLength
)) {
Status = ERROR_NO_UNICODE_TRANSLATION;
}
else {
Status = WmiSetSingleInstance( hWmiHandle,
cstr,
1,
BufferSize,
Buffer
);
}
#else
Status = WmiSetSingleInstance( hWmiHandle,
pInterface->pTcIfc->InstanceName,
1,
BufferSize,
Buffer
);
#endif
} __except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
IF_DEBUG(ERRORS) {
WSPRINT(("TcSetInterface: Exception Error: = 0x%X\n",
Status ));
}
}
}
WmiCloseBlock(hWmiHandle);
if (pWnode)
FreeMem(pWnode);
REFDEL(&pInterface->RefCount, 'TCSI');
return Status;
}
/*
************************************************************************
Description:
Will issue a WMI query on the specific flow instance name.
Arguments:
pFlowName - flow instance name
pGuidParam - GUID of the queried property
BufferSize - size of allocated buffer
Buffer - the buffer for returned result
Return Value:
NO_ERROR
ERROR_INVALID_PARAMETER bad parameter
ERROR_INSUFFICIENT_BUFFER buffer too small for result
ERROR_NOT_SUPPORTED unsupported GUID
ERROR_WMI_GUID_NOT_FOUND
ERROR_WMI_INSTANCE_NOT_FOUND
************************************************************************
*/
DWORD
APIENTRY
TcQueryFlowW(
IN LPWSTR pFlowName,
IN LPGUID pGuidParam,
IN OUT PULONG pBufferSize,
OUT PVOID Buffer
)
{
DWORD Status;
HANDLE hWmiHandle;
TCHAR cstr[MAX_STRING_LENGTH];
PWNODE_SINGLE_INSTANCE pWnode;
ULONG cBufSize;
ULONG InputBufferSize;
if (IsBadWritePtr(pBufferSize, sizeof(ULONG)))
{
return ERROR_INVALID_PARAMETER;
}
__try {
InputBufferSize = *pBufferSize;
*pBufferSize = 0;
} __except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
IF_DEBUG(ERRORS) {
WSPRINT(("TcSetFlowW: Exception Error: = 0x%X\n",
Status ));
}
return Status;
}
if ( IsBadReadPtr(pGuidParam, sizeof(GUID))
|| IsBadStringPtr(pFlowName, MAX_STRING_LENGTH)
|| IsBadWritePtr(Buffer,InputBufferSize) )
{
return ERROR_INVALID_PARAMETER;
}
Status = WmiOpenBlock(pGuidParam, // object
0, // access
&hWmiHandle);
if (ERROR_FAILED(Status)) {
TC_TRACE(ERRORS, ("[TcQueryInterface]: WmiOpenBlock Error: = 0x%X\n", Status ));
return Status;
}
//
// allocate memory for the output wnode
//
cBufSize = sizeof(WNODE_SINGLE_INSTANCE)
+ InputBufferSize
+ MAX_STRING_LENGTH * sizeof(TCHAR);
AllocMem(&pWnode, cBufSize);
if (pWnode == NULL) {
Status = ERROR_NOT_ENOUGH_MEMORY;
}
else
{
//
// query for the single instance
//
#ifndef UNICODE
if (-1 == wcstombs(cstr,
pFlowName,
wcslen(pFlowName)
))
{
Status = ERROR_NO_UNICODE_TRANSLATION;
}
else
{
Status = WmiQuerySingleInstance( hWmiHandle,
cstr,
&cBufSize,
pWnode
);
}
#else
Status = WmiQuerySingleInstance( hWmiHandle,
pFlowName,
&cBufSize,
pWnode
);
#endif
if (!ERROR_FAILED(Status)) {
//
// parse the wnode
//
//
// check to see if the user allocated enough space for the
// returned buffer
//
if (pWnode->SizeDataBlock <= InputBufferSize) {
__try {
RtlCopyMemory(Buffer,
(PBYTE)OffsetToPtr(pWnode, pWnode->DataBlockOffset),
pWnode->SizeDataBlock
);
*pBufferSize = pWnode->SizeDataBlock;
} __except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
TC_TRACE(ERRORS, ("[TcQueryInterface]: RtlCopyMemory Exception Error: = 0x%X\n", Status ));
}
} else {
//
// output buffer too small
//
__try {
*pBufferSize = pWnode->SizeDataBlock;
Status = ERROR_INSUFFICIENT_BUFFER;
} __except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
TC_TRACE(ERRORS, ("[TcQueryInterface]: RtlCopyMemory Exception Error: = 0x%X\n", Status ));
}
}
}
}
WmiCloseBlock(hWmiHandle);
if(pWnode)
FreeMem(pWnode);
return Status;
}
/*
************************************************************************
Description:
The ANSI version of TcQueryFlowW
Arguments:
See TcQueryFlowW
Return Value:
See TcQueryFlowW
************************************************************************
*/
DWORD
APIENTRY
TcQueryFlowA(
IN LPSTR pFlowName,
IN LPGUID pGuidParam,
IN OUT PULONG pBufferSize,
OUT PVOID Buffer
)
{
LPWSTR pWstr = NULL;
int l;
DWORD Status;
if (IsBadStringPtrA(pFlowName,MAX_STRING_LENGTH)) {
return ERROR_INVALID_PARAMETER;
}
l = strlen(pFlowName) + 1;
AllocMem(&pWstr, l*sizeof(WCHAR));
if (pWstr == NULL) {
return ERROR_NOT_ENOUGH_MEMORY;
}
if (-1 == mbstowcs(pWstr, pFlowName, l)) {
FreeMem(pWstr);
return ERROR_NO_UNICODE_TRANSLATION;
}
Status = TcQueryFlowW(pWstr,
pGuidParam,
pBufferSize,
Buffer
);
FreeMem(pWstr);
return Status;
}
/*
************************************************************************
Description:
Will issue a WMI set on the specific flow instance name.
Arguments:
pFlowName - flow instance name
pGuidParam - GUID of the queried property
BufferSize - size of allocated buffer
Buffer - the buffer to set
Return Value:
NO_ERROR
ERROR_INVALID_PARAMETER bad parameter
ERROR_INSUFFICIENT_BUFFER buffer too small for result
ERROR_NOT_SUPPORTED unsupported GUID
ERROR_WMI_GUID_NOT_FOUND
ERROR_WMI_INSTANCE_NOT_FOUND
************************************************************************
*/
DWORD
APIENTRY
TcSetFlowW(
IN LPWSTR pFlowName,
IN LPGUID pGuidParam,
IN ULONG BufferSize,
IN PVOID Buffer
)
{
DWORD Status;
HANDLE hWmiHandle;
TCHAR cstr[MAX_STRING_LENGTH];
PWNODE_SINGLE_INSTANCE pWnode;
ULONG cBufSize;
if ( IsBadStringPtr(pFlowName,MAX_STRING_LENGTH)
|| IsBadReadPtr(pGuidParam,sizeof(GUID))
|| (BufferSize == 0)
|| IsBadReadPtr(Buffer,BufferSize)) {
return ERROR_INVALID_PARAMETER;
}
Status = WmiOpenBlock( pGuidParam, // object
0, // access
&hWmiHandle
);
if (ERROR_FAILED(Status)) {
TC_TRACE(ERRORS, ("[TcSetFlow]: WmiOpenBlock failed with 0x%x \n", Status));
return Status;
}
//
// allocate memory for the output wnode
//
cBufSize = sizeof(WNODE_SINGLE_INSTANCE)
+ BufferSize
+ MAX_STRING_LENGTH * sizeof(TCHAR);
AllocMem(&pWnode, cBufSize);
if (pWnode == NULL) {
Status = ERROR_NOT_ENOUGH_MEMORY;
} else {
//
// set the single instance
//
__try {
#ifndef UNICODE
if (-1 == wcstombs(cstr,
pFlowName,
wcslen(pFlowName)
)) {
Status = ERROR_NO_UNICODE_TRANSLATION;
} else {
Status = WmiQuerySingleInstance( hWmiHandle,
cstr,
&cBufSize,
pWnode
);
}
#else
Status = WmiSetSingleInstance( hWmiHandle,
pFlowName,
1,
BufferSize,
Buffer
);
#endif
} __except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
IF_DEBUG(ERRORS) {
WSPRINT(("TcSetFlowW: Exception Error: = 0x%X\n",
Status ));
}
}
}
WmiCloseBlock(hWmiHandle);
if (pWnode)
FreeMem(pWnode);
return Status;
}
/*
************************************************************************
Description:
The ANSI version of TcSetFlowW
Arguments:
See TcSetFlowW
Return Value:
See TcSetFlowW
************************************************************************
*/
DWORD
APIENTRY
TcSetFlowA(
IN LPSTR pFlowName,
IN LPGUID pGuidParam,
IN ULONG BufferSize,
IN PVOID Buffer
)
{
LPWSTR pWstr;
int l;
DWORD Status;
if (IsBadStringPtrA(pFlowName,MAX_STRING_LENGTH)) {
return ERROR_INVALID_PARAMETER;
}
l = strlen(pFlowName) + 1;
AllocMem(&pWstr, l*sizeof(WCHAR));
if (pWstr == NULL) {
return ERROR_NOT_ENOUGH_MEMORY;
}
if(-1 == mbstowcs(pWstr, pFlowName, l)) {
// couldn't convert some multibyte characters - bail with error.
FreeMem(pWstr);
return ERROR_NO_UNICODE_TRANSLATION;
}
Status = TcSetFlowW(pWstr,
pGuidParam,
BufferSize,
Buffer
);
FreeMem(pWstr);
return Status;
}
/*
************************************************************************
Description:
Will return the flow inatsnace name associated with the flow handle.
Arguments:
FlowHandle - the flow handle
StrSize - how many TCHAR can fit in the string buffer
pFlowName - a pointer to a string buffer
Return Value:
See TcGetFlowNameW
************************************************************************
*/
DWORD
APIENTRY
TcGetFlowNameW(
IN HANDLE FlowHandle,
IN ULONG StrSize,
OUT LPWSTR pFlowName
)
{
PFLOW_STRUC pFlow;
DWORD Status;
VERIFY_INITIALIZATION_STATUS;
if (IsBadWritePtr(pFlowName,StrSize*sizeof(WCHAR))) {
return ERROR_INVALID_PARAMETER;
}
pFlow = (PFLOW_STRUC)GetHandleObjectWithRef(FlowHandle, ENUM_GEN_FLOW_TYPE, 'TGFW');
if (pFlow == NULL) {
return ERROR_INVALID_HANDLE;
}
else if (pFlow == INVALID_HANDLE_VALUE )
{
Status = ERROR_NOT_READY;
IF_DEBUG(ERRORS) {
WSPRINT(("TcGetFlowNameW: Error = 0x%X\n", Status ));
}
return ERROR_NOT_READY;
}
ASSERT((HANDLE)pFlow->ClHandle == FlowHandle);
if (pFlow->InstanceNameLength+sizeof(WCHAR) > (USHORT)StrSize) {
//IF_DEBUG(REFCOUNTS) { WSPRINT(("8\n"));
IF_DEBUG(REFCOUNTS) {
WSPRINT(("8 DEREF FLOW %X (%X) ref(%d)\n", pFlow->ClHandle, pFlow, pFlow->RefCount));
}
REFDEL(&pFlow->RefCount, 'TGFW');
return ERROR_INSUFFICIENT_BUFFER;
}
__try {
wcscpy(pFlowName, pFlow->InstanceName);
} __except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
IF_DEBUG(ERRORS) {
WSPRINT(("TcGetFlowName: Exception Error: = 0x%X\n", Status ));
}
REFDEL(&pFlow->RefCount, 'TGFW');
return Status;
}
IF_DEBUG(REFCOUNTS) {
WSPRINT(("9 DEREF FLOW %X (%X) ref(%d)\n", pFlow->ClHandle, pFlow, pFlow->RefCount));
}
REFDEL(&pFlow->RefCount, 'TGFW');
return NO_ERROR;
}
/*
************************************************************************
Description:
The ANSI version of TcGetFlowNameW
Arguments:
See TcGetFlowNameW
Return Value:
See TcGetFlowNameW
************************************************************************
*/
DWORD
APIENTRY
TcGetFlowNameA(
IN HANDLE FlowHandle,
IN ULONG StrSize,
OUT LPSTR pFlowName
)
{
PFLOW_STRUC pFlow;
DWORD Status = NO_ERROR;
VERIFY_INITIALIZATION_STATUS;
if (IsBadWritePtr(pFlowName,StrSize * sizeof(CHAR))) {
return ERROR_INVALID_PARAMETER;
}
pFlow = (PFLOW_STRUC)GetHandleObjectWithRef(FlowHandle, ENUM_GEN_FLOW_TYPE, 'TGFA');
if (pFlow == NULL) {
return ERROR_INVALID_HANDLE;
}
else if (pFlow == INVALID_HANDLE_VALUE )
{
Status = ERROR_NOT_READY;
IF_DEBUG(ERRORS) {
WSPRINT(("TcGetFlowNameA: Error = 0x%X\n", Status ));
}
return ERROR_NOT_READY;
}
ASSERT((HANDLE)pFlow->ClHandle == FlowHandle);
if (pFlow->InstanceNameLength+sizeof(CHAR) > (USHORT)StrSize) {
IF_DEBUG(REFCOUNTS) {
WSPRINT(("11 DEREF FLOW %X (%X) ref(%d)\n", pFlow->ClHandle, pFlow, pFlow->RefCount));
}
REFDEL(&pFlow->RefCount, 'TGFA');
return ERROR_INSUFFICIENT_BUFFER;
}
__try {
if (-1 == wcstombs(
pFlowName,
pFlow->InstanceName,
pFlow->InstanceNameLength)) {
Status = ERROR_NO_UNICODE_TRANSLATION;
}
} __except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
IF_DEBUG(ERRORS) {
WSPRINT(("TcGetFlowName: Exception Error: = 0x%X\n", Status ));
}
REFDEL(&pFlow->RefCount, 'TGFA');
return Status;
}
IF_DEBUG(REFCOUNTS) {
WSPRINT(("12 DEREF FLOW %X (%X) ref(%d)\n", pFlow->ClHandle, pFlow, pFlow->RefCount));
}
REFDEL(&pFlow->RefCount, 'TGFA');
return Status;
}
/*
************************************************************************
Description:
This will return a specified number of flows with their respective
filter, given the buffer is big enough. The user allocates the buffer,
and passes a pointer to an enumeration token. This will be used
by the GPC to keep track what was the last enumerated flow and will
initially be point to a NULL value (reset by TC_RESET_ENUM_TOKEN).
The user will also pass the number of requested flow and will get back
the actual number of flows that have been placed in the buffer.
If the buffer is too small, an error code will be returned. If there are
no more flows to enumerate, NO_ERROR will be returned and pFlowCount
will be set to zero. It is invalid to request zero flows
Arguments:
IfcHandle - the interface to enumerate flows on
pEnumToken - enumeration handles pointer,
user must not change after the first call
pFlowCount - in: # of requested flows; out: actual # of flows returned
pBufSize - in: allocated bytes; out: filled bytes
Buffer - formatted data
Return Value:
NO_ERROR
ERROR_INVALID_HANDLE bad interface handle
ERROR_INVALID_PARAMETER one of the pointers is null or either
pFlowCount or pBufSize are set to zero
ERROR_INSUFFICIENT_BUFFER indicates that the provided buffer is too
small to return even the information for a
single flow and the attached filters.
ERROR_NOT_ENOUGH_MEMORY out of memory
ERROR_INVALID_DATA enumeration handle no longer valid
************************************************************************
*/
DWORD
APIENTRY
TcEnumerateFlows(
IN HANDLE IfcHandle,
IN OUT PHANDLE pEnumHandle,
IN OUT PULONG pFlowCount,
IN OUT PULONG pBufSize,
OUT PENUMERATION_BUFFER Buffer
)
{
DWORD Status;
PINTERFACE_STRUC pInterface;
PGPC_ENUM_CFINFO_RES OutBuffer;
ULONG cFlows;
ULONG BufSize;
ULONG TotalFlows;
ULONG TotalBytes;
PFLOW_STRUC pFlow;
PGPC_CLIENT pGpcClient;
PLIST_ENTRY pHead, pEntry;
GPC_HANDLE GpcFlowHandle;
PGPC_ENUM_CFINFO_BUFFER pGpcEnumBuf;
PCF_INFO_QOS pCfInfo;
ULONG Len, i, j;
ULONG GenFlowSize;
PCHAR p;
BOOLEAN bMore;
PTC_GEN_FILTER pFilter;
PGPC_GEN_PATTERN pPattern;
ULONG InputBufSize;
ULONG InputFlowCount;
VERIFY_INITIALIZATION_STATUS;
IF_DEBUG(CALLS) {
WSPRINT(("==>TcEnumerateFlows: Called: IfcHandle= %d",
IfcHandle ));
}
if ( IsBadWritePtr(pBufSize, sizeof(ULONG))
|| IsBadWritePtr(pFlowCount, sizeof(ULONG))
|| IsBadWritePtr(pEnumHandle,sizeof(HANDLE)) ) {
return ERROR_INVALID_PARAMETER;
}
__try {
InputBufSize = *pBufSize;
// *pBufSize = 0; // reset it in case of an error
InputFlowCount = *pFlowCount;
GpcFlowHandle = *pEnumHandle;
} __except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
return Status;
}
if ( IsBadWritePtr(Buffer, InputBufSize)
|| (InputFlowCount == 0) ) {
return ERROR_INVALID_PARAMETER;
}
if (InputBufSize == 0) {
return ERROR_INSUFFICIENT_BUFFER;
}
pInterface = (PINTERFACE_STRUC)GetHandleObjectWithRef(IfcHandle,
ENUM_INTERFACE_TYPE, 'TCEF');
if (pInterface == NULL) {
return ERROR_INVALID_HANDLE;
}
pGpcClient = FindGpcClient(GPC_CF_QOS);
if (pGpcClient == NULL) {
REFDEL(&pInterface->RefCount, 'TCEF');
return ERROR_DEV_NOT_EXIST;
}
//
// We are enumerating flows on the interface. we cant afford to have the
// flows deleted from teh list, therefore we shall take the global lock here.
//
GetLock(pGlobals->Lock);
// back to regularly scheduled programming
TotalFlows = 0;
TotalBytes = 0;
bMore = TRUE;
while (bMore) {
BufSize = InputBufSize - TotalBytes;
cFlows = InputFlowCount - TotalFlows;
Status = IoEnumerateFlows(pGpcClient,
&GpcFlowHandle,
&cFlows,
&BufSize,
&OutBuffer
);
if (!ERROR_FAILED(Status)) {
//
// parse the output buffer and return only the flows that have the
// interface name in them
//
pGpcEnumBuf = &OutBuffer->EnumBuffer[0];
for (i = 0; i < cFlows; i++) {
//
// get the CfInfo
//
pCfInfo = (PCF_INFO_QOS)((PCHAR)pGpcEnumBuf +
pGpcEnumBuf->CfInfoOffset);
//
// check if this flow belongs to this interface
//
if (wcscmp(pCfInfo->InstanceName,
pInterface->pTcIfc->InstanceName) == 0) {
//
// the flow is installed on this instance
//
GenFlowSize = FIELD_OFFSET(TC_GEN_FLOW, TcObjects)
+ pCfInfo->GenFlow.TcObjectsLength;
//
// The GPC used GPC_GEN_PATTERN when it computed
// PatternMaskLen. But, we are using TC_GEN_FILTER
// to display the patterns. So, we need to account
// for the difference in GPC_GEN_PATTERN and
// TC_GEN_FILTER.
//
// No, this cannot be made cleaner by getting the GPC
// to use TC_GEN_FILTER. The GPC is a generic packet
// classifier and hence shouldn't know about TC_GEN_FILTER.
//
Len = FIELD_OFFSET(ENUMERATION_BUFFER, GenericFilter)
+ GenFlowSize
+ pGpcEnumBuf->PatternMaskLen
- pGpcEnumBuf->PatternCount * sizeof(GPC_GEN_PATTERN)
+ pGpcEnumBuf->PatternCount * sizeof(TC_GEN_FILTER);
Len = ((Len + (sizeof(PVOID)-1)) & ~(sizeof(PVOID)-1));
if (TotalBytes + Len > InputBufSize) {
//
// not enough buffer output space
//
if (TotalFlows == 0)
Status = ERROR_INSUFFICIENT_BUFFER;
bMore = FALSE;
break;
}
//
// fill the output buffer
//
__try {
Buffer->Length = Len;
Buffer->OwnerProcessId = PtrToUlong(pGpcEnumBuf->OwnerClientCtx);
Buffer->FlowNameLength = pGpcEnumBuf->InstanceNameLength;
wcscpy(Buffer->FlowName, pGpcEnumBuf->InstanceName);
Buffer->NumberOfFilters = pGpcEnumBuf->PatternCount;
pFilter = (PTC_GEN_FILTER)
((PCHAR)Buffer
+ FIELD_OFFSET(ENUMERATION_BUFFER, GenericFilter));
} __except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
break;
}
pPattern = &pGpcEnumBuf->GenericPattern[0];
//
// fill the filters
//
for (j = 0; j < pGpcEnumBuf->PatternCount; j++) {
switch(pPattern->ProtocolId) {
case GPC_PROTOCOL_TEMPLATE_IP:
pFilter->AddressType = NDIS_PROTOCOL_ID_TCP_IP;
ASSERT(pPattern->PatternSize
== sizeof(IP_PATTERN));
break;
case GPC_PROTOCOL_TEMPLATE_IPX:
pFilter->AddressType = NDIS_PROTOCOL_ID_IPX;
ASSERT(pPattern->PatternSize
== sizeof(IPX_PATTERN));
break;
default:
ASSERT(0);
}
pFilter->PatternSize = pPattern->PatternSize ;
pFilter->Pattern = (PVOID)((PCHAR)pFilter
+ sizeof(TC_GEN_FILTER));
pFilter->Mask = (PVOID)((PCHAR)pFilter->Pattern
+ pPattern->PatternSize);
//
// copy the pattern
//
p = ((PUCHAR)pPattern) + pPattern->PatternOffset;
RtlCopyMemory(pFilter->Pattern,
p,
pPattern->PatternSize);
//
// copy the mask
//
p = ((PUCHAR)pPattern) + pPattern->MaskOffset;
RtlCopyMemory(pFilter->Mask,
p,
pPattern->PatternSize);
//
// advance the filter pointer to the next item
//
pFilter = (PTC_GEN_FILTER)
((PCHAR)pFilter
+ sizeof(TC_GEN_FILTER)
+ pPattern->PatternSize * 2);
pPattern = (PGPC_GEN_PATTERN)(p + pPattern->PatternSize);
} // for (...)
//
// fill the flow
//
__try {
Buffer->pFlow = (PTC_GEN_FLOW)pFilter;
RtlCopyMemory(pFilter,
&pCfInfo->GenFlow,
GenFlowSize
);
//
// advance to the next available slot in
// the output buffer
//
Buffer = (PENUMERATION_BUFFER)((PCHAR)Buffer + Len);
} __except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
break;
}
//
// update total counts
//
TotalBytes += Len;
TotalFlows++;
}
//
// advance to the next entry in the GPC returned buffer
//
pGpcEnumBuf = (PGPC_ENUM_CFINFO_BUFFER)((PCHAR)pGpcEnumBuf
+ pGpcEnumBuf->Length);
}
//
// release the buffer
//
FreeMem(OutBuffer);
//
// check to see if we still have room for more flows
// and adjust the call parameters
//
if (TotalFlows == InputFlowCount ||
TotalBytes + sizeof(ENUMERATION_BUFFER) > InputBufSize ) {
//
// that's it, stop enumerating here
//
break;
}
//
// check the GpcFlowHandle and quit if needed
//
if (GpcFlowHandle == NULL) {
break;
}
} else {
//
// there was some error returned,
// we still have to check if that's the first call
//
//
if (Status == ERROR_INVALID_DATA) {
__try {
*pEnumHandle = NULL;
} __except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
}
} else if (TotalFlows > 0) {
Status = NO_ERROR;
}
break;
}
} // while
if (!ERROR_FAILED(Status)) {
__try {
*pEnumHandle = GpcFlowHandle;
*pFlowCount = TotalFlows;
*pBufSize = TotalBytes;
} __except (EXCEPTION_EXECUTE_HANDLER) {
Status = GetExceptionCode();
}
}
//
// Free all the flow refs taken at the start.
//
FreeLock(pGlobals->Lock);
REFDEL(&pInterface->RefCount, 'TCEF');
IF_DEBUG(CALLS) {
WSPRINT(("<==TcEnumerateFlows: Returned= 0x%X\n", Status ));
}
return Status;
}
/*
************************************************************************
Description:
This call will add a new Class Map flow on the interface.
Arguments:
IfcHandle - the interface handle to add the flow on
ClFlowCtx - a client given flow context
AddressType - determines what protocol template to use with the GPC
Flags - reserved, will be used to indicate a persistent flow
pClassMapFlow - class map flow
pFlowHandle - returned flow handle in case of success
Return Value:
NO_ERROR
ERROR_SIGNAL_PENDING
General error codes:
ERROR_INVALID_HANDLE bad handle.
ERROR_NOT_ENOUGH_MEMORY system out of memory
ERROR_INVALID_PARAMETER a general parameter is invalid
TC specific error codes:
ERROR_INVALID_TRAFFIC_CLASS invalid traffic class value
ERROR_NO_SYSTEM_RESOURCES not enough resources to accommodate flows
************************************************************************
*/
DWORD
APIENTRY
TcAddClassMap(
IN HANDLE IfcHandle,
IN HANDLE ClFlowCtx,
IN ULONG Flags,
IN PTC_CLASS_MAP_FLOW pClassMapFlow,
OUT PHANDLE pFlowHandle
)
{
DWORD Status;
PFLOW_STRUC pFlow;
PINTERFACE_STRUC pInterface;
PCLIENT_STRUC pClient;
PGPC_CLIENT pGpcClient;
return ERROR_CALL_NOT_IMPLEMENTED;
#if NEVER
// As this is not published in MSDN and not implemented in PSCHED also
IF_DEBUG(CALLS) {
WSPRINT(("==>TcAddClassMap: Called: IfcHandle= %d, ClFlowCtx=%d\n",
IfcHandle, ClFlowCtx ));
}
if (pFlowHandle) {
*pFlowHandle = TC_INVALID_HANDLE;
}
VERIFY_INITIALIZATION_STATUS;
if (pFlowHandle == NULL || pClassMapFlow == NULL) {
Status = ERROR_INVALID_PARAMETER;
IF_DEBUG(ERRORS) {
WSPRINT(("TcAddClassMap: Error = 0x%X\n", Status ));
}
return Status;
}
*pFlowHandle = TC_INVALID_HANDLE;
pInterface = (PINTERFACE_STRUC)GetHandleObjectWithRef(IfcHandle,
ENUM_INTERFACE_TYPE, 'TACM');
if (pInterface == NULL) {
Status = ERROR_INVALID_HANDLE;
IF_DEBUG(ERRORS) {
WSPRINT(("TcAddClassMap: Error = 0x%X\n", Status ));
}
return Status;
}
ASSERT((HANDLE)pInterface->ClHandle == IfcHandle);
//
// search for an open GPC client that supports this address type
//
pGpcClient = FindGpcClient(GPC_CF_CLASS_MAP);
if (pGpcClient == NULL) {
//
// not found!
//
Status = ERROR_ADDRESS_TYPE_NOT_SUPPORTED;
IF_DEBUG(ERRORS) {
WSPRINT(("TcAddClassMap: Error = 0x%X\n", Status ));
}
REFDEL(&pInterface->RefCount, 'TACM');
return Status;
}
//
// create a new flow structure
//
Status = CreateClassMapFlowStruc(ClFlowCtx, pClassMapFlow, &pFlow);
if (ERROR_FAILED(Status)) {
IF_DEBUG(ERRORS) {
WSPRINT(("TcAddClassMap: Error = 0x%X\n", Status ));
}
REFDEL(&pInterface->RefCount, 'TACM');
return Status;
}
pClient = pInterface->pClient;
//
// initialize the flow structure and add it on the intefrace list
//
pFlow->pInterface = pInterface;
pFlow->Flags = Flags | TC_FLAGS_INSTALLING;
pFlow->pGpcClient = pGpcClient;
GetLock(pGlobals->Lock);
InsertTailList(&pInterface->FlowList, &pFlow->Linkage);
pInterface->FlowCount++;
REFADD(&pInterface->RefCount, 'FLOW');
FreeLock(pGlobals->Lock);
//
// call to actually add the flow
//
Status = IoAddClassMapFlow( pFlow, TRUE );
if (!ERROR_FAILED(Status)) {
*pFlowHandle = (HANDLE)pFlow->ClHandle;
}
if (!ERROR_PENDING(Status)) {
//
// call completed, either success or failure...
//
CompleteAddFlow(pFlow, Status);
}
//
// !!! don't reference pFlow after this since it may be gone!!!
//
IF_DEBUG(CALLS) {
WSPRINT(("<==TcAddClassMap: Returned= 0x%X\n", Status ));
}
REFDEL(&pInterface->RefCount, 'TACM');
return Status;
#endif
}