/*++ Copyright (c) 1996-1997 Microsoft Corporation Module Name: apiutil.c Abstract: This module contains the traffic control api utils Author: Jim Stewart ( jstew ) August 22, 1996 Revision History: Ofer Bar (oferbar) Oct 1, 1997 --*/ #include "precomp.h" #pragma hdrstop #include #define INITGUID #include "ntddtc.h" static BOOLEAN _init = FALSE; #if 0 // Name of the DLL to load const CHAR IpHlpApiDllName[] = "iphlpapi"; // Names of the functions called in IPHLPAPI const CHAR GET_IF_ENTRY[] = "GetIfEntry"; const CHAR GET_IP_ADDR_TABLE[] = "GetIpAddrTable"; const CHAR GET_BEST_ROUTE[] = "GetBestRoute"; IPROUTE_IF IpRouteTab; #endif TCHAR SzBuf[MAX_PATH]; // VOID MarkAllNodesForClosing( PINTERFACE_STRUC pInterface, STATE stateToMark ) /*++ Description: This routine will mark all flows and filters on a INTERFACE_STRUC (a client's interface struct) as close FORCED_KERNELCLOSE or EXIT_CLEANUP. Please note that it is already called with the global lock held. Arguments: pInterface - ptr to the interface stateToMark - the state to mark the nodes (FORCED_KERNELCLOSE or EXIT_CLEANUP) Return Value: nothing --*/ { PLIST_ENTRY pEntry, pFilterEntry; PFLOW_STRUC pFlow; PFILTER_STRUC pFilter; ASSERT((stateToMark == FORCED_KERNELCLOSE) || (stateToMark == EXIT_CLEANUP)); pEntry = pInterface->FlowList.Flink; while (pEntry != &pInterface->FlowList) { pFlow = CONTAINING_RECORD(pEntry, FLOW_STRUC, Linkage); // // For each flow and filter, first check if the user is trying to close it // if that is the case, do nothing, otherwise, mark it GetLock(pFlow->Lock); if (QUERY_STATE(pFlow->State) == OPEN) { // Cleanup from under teh user... SET_STATE(pFlow->State, stateToMark); } else { ASSERT(IsListEmpty(&pFlow->FilterList)); // There's nothing to be done here. IF_DEBUG(WARNINGS) { WSPRINT(("Against a forced close - Flow is removed by the user\n", pFlow)); } } pFilterEntry = pFlow->FilterList.Flink; while (pFilterEntry != &pFlow->FilterList) { pFilter = CONTAINING_RECORD(pFilterEntry, FILTER_STRUC, Linkage); GetLock(pFilter->Lock); if (QUERY_STATE(pFilter->State) == OPEN) { // Cleanup from under teh user... SET_STATE(pFilter->State, stateToMark); } else { // There's nothing to be done here. IF_DEBUG(WARNINGS) { WSPRINT(("Against a forced close - Filter is removed by the user\n", pFilter)); } } pFilterEntry = pFilterEntry->Flink; FreeLock(pFilter->Lock); } pEntry = pEntry->Flink; FreeLock(pFlow->Lock); } } VOID CloseOpenFlows( IN PINTERFACE_STRUC pInterface ) /*++ Description: This routine closes any flows that are open on an interface. Arguments: pInterface - ptr to the interface Return Value: nothing --*/ { DWORD Status = NO_ERROR; PLIST_ENTRY pEntry; PFLOW_STRUC pFlow; GetLock( pGlobals->Lock ); pEntry = pInterface->FlowList.Flink; while (pEntry != &pInterface->FlowList) { pFlow = CONTAINING_RECORD( pEntry, FLOW_STRUC, Linkage ); GetLock(pFlow->Lock); if ((QUERY_STATE(pFlow->State) == FORCED_KERNELCLOSE) || (QUERY_STATE(pFlow->State) == EXIT_CLEANUP)) { pEntry = pEntry->Flink; FreeLock(pFlow->Lock); IF_DEBUG(SHUTDOWN) { WSPRINT(( "Closing Flow: 0x%X\n", pFlow)); } Status = DeleteFlow( pFlow, TRUE ); IF_DEBUG(SHUTDOWN) { WSPRINT(("CloseOpenFlows: DeleteFlow returned=0x%X\n", Status)); } } else { pEntry = pEntry->Flink; FreeLock(pFlow->Lock); } } FreeLock( pGlobals->Lock ); } VOID CloseOpenFilters( IN PFLOW_STRUC pFlow ) /*++ Description: This routine closes any filters that are open on a flow. Arguments: pFlow - ptr to the flow Return Value: nothing --*/ { DWORD Status = NO_ERROR; PLIST_ENTRY pEntry; PFILTER_STRUC pFilter; IF_DEBUG(SHUTDOWN) { WSPRINT(( "CloseOpenFilters: Closing all Open Filters\n" )); } GetLock( pGlobals->Lock ); pEntry = pFlow->FilterList.Flink; while (pEntry != &pFlow->FilterList) { pFilter = CONTAINING_RECORD( pEntry, FILTER_STRUC, Linkage ); GetLock(pFilter->Lock); if ((QUERY_STATE(pFilter->State) == FORCED_KERNELCLOSE) || (QUERY_STATE(pFilter->State) == EXIT_CLEANUP)) { // we can take a ref here, but we own it anyways! pEntry = pEntry->Flink; FreeLock(pFilter->Lock); Status = DeleteFilter( pFilter ); IF_DEBUG(SHUTDOWN) { WSPRINT(( "CloseOpenFilters: DeleteFilter returned=0x%X\n", Status)); } //ASSERT(Status == NO_ERROR); } else { pEntry = pEntry->Flink; FreeLock(pFilter->Lock); IF_DEBUG(SHUTDOWN) { WSPRINT(( "CloseOpenFilters: DeleteFilter (%x) was skipped because its state (%d)\n", pFilter, pFilter->State)); } } } FreeLock( pGlobals->Lock ); } VOID DeleteFlowStruc( IN PFLOW_STRUC pFlow ) /*++ Description: This routine frees the handle and memory associated with the structure. Arguments: pFlow - ptr to the flow Return Value: nothing --*/ { if(pFlow->PendingEvent) CloseHandle(pFlow->PendingEvent); DeleteLock(pFlow->Lock); if (pFlow->pGenFlow) { FreeMem(pFlow->pGenFlow); pFlow->GenFlowLen = 0; } if (pFlow->pGenFlow1) { FreeMem(pFlow->pGenFlow1); pFlow->GenFlowLen1 = 0; } if (pFlow->pClassMapFlow) FreeMem(pFlow->pClassMapFlow); if (pFlow->pClassMapFlow1) FreeMem(pFlow->pClassMapFlow1); FreeMem(pFlow); } VOID DeleteFilterStruc( IN PFILTER_STRUC pFilter ) /*++ Description: This routine frees the handle and memory associated with the structure. Arguments: pFIlter Return Value: nothing --*/ { if (pFilter->pGpcFilter) FreeMem(pFilter->pGpcFilter); DeleteLock(pFilter->Lock); FreeMem(pFilter); } PTC_IFC GetTcIfc( IN LPWSTR pInterfaceName ) { PTC_IFC pIfc = NULL; PLIST_ENTRY pHead, pEntry; DWORD Status = NO_ERROR; GetLock(pGlobals->Lock); pHead = &pGlobals->TcIfcList; pEntry = pHead->Flink; while (pEntry != pHead && pIfc == NULL) { pIfc = CONTAINING_RECORD(pEntry, TC_IFC, Linkage); __try { if (wcsncmp(pInterfaceName, pIfc->InstanceName, wcslen(pIfc->InstanceName)) != 0) { // // not found // pIfc = NULL; } } __except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); IF_DEBUG(ERRORS) { WSPRINT(("GetTcIfc: Invalid pInterfaceName(%x) Exception: = 0x%X\n", pInterfaceName, Status )); } FreeLock(pGlobals->Lock); return NULL; } pEntry = pEntry->Flink; } FreeLock(pGlobals->Lock); return pIfc; } PTC_IFC GetTcIfcWithRef( IN LPWSTR pInterfaceName, IN ULONG RefType ) { PTC_IFC pIfc = NULL; PLIST_ENTRY pHead, pEntry; DWORD Status = NO_ERROR; GetLock(pGlobals->Lock); pHead = &pGlobals->TcIfcList; pEntry = pHead->Flink; while (pEntry != pHead && pIfc == NULL) { pIfc = CONTAINING_RECORD(pEntry, TC_IFC, Linkage); __try { if (wcsncmp(pInterfaceName, pIfc->InstanceName, wcslen(pIfc->InstanceName)) != 0) { // // not found // pIfc = NULL; } } __except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); IF_DEBUG(ERRORS) { WSPRINT(("GetTcIfc: Invalid pInterfaceName(%x) Exception: = 0x%X\n", pInterfaceName, Status )); } FreeLock(pGlobals->Lock); return NULL; } pEntry = pEntry->Flink; } if (pIfc) { GetLock(pIfc->Lock); if (QUERY_STATE(pIfc->State)== OPEN) { FreeLock(pIfc->Lock); REFADD(&pIfc->RefCount, RefType); FreeLock(pGlobals->Lock); return pIfc; } else { FreeLock(pIfc->Lock); FreeLock(pGlobals->Lock); return NULL; } } else { FreeLock(pGlobals->Lock); return NULL; } } DWORD UpdateTcIfcList( IN LPWSTR InstanceName, IN ULONG IndicationBufferSize, IN PTC_INDICATION_BUFFER IndicationBuffer, IN DWORD IndicationCode ) { DWORD Status = NO_ERROR; PTC_IFC pTcIfc; ULONG l; PADDRESS_LIST_DESCRIPTOR pAddrListDesc; switch (IndicationCode) { case TC_NOTIFY_IFC_UP: // // Allocate a new interface descriptor structure // l = IndicationBufferSize - FIELD_OFFSET(TC_INDICATION_BUFFER,InfoBuffer) - FIELD_OFFSET(TC_SUPPORTED_INFO_BUFFER, AddrListDesc); CreateKernelInterfaceStruc(&pTcIfc, l); if (pTcIfc) { // // copy the instance name string data // wcscpy(pTcIfc->InstanceName, InstanceName); pTcIfc->InstanceNameLength = wcslen(InstanceName) * sizeof(WCHAR); // // copy the instance ID string data // pTcIfc->InstanceIDLength = IndicationBuffer->InfoBuffer.InstanceIDLength; memcpy((PVOID)pTcIfc->InstanceID, (PVOID)IndicationBuffer->InfoBuffer.InstanceID, pTcIfc->InstanceIDLength); pTcIfc->InstanceID[pTcIfc->InstanceIDLength/sizeof(WCHAR)] = L'\0'; // // copy the instance data // in this case - the network address // pTcIfc->AddrListBytesCount = l; RtlCopyMemory( pTcIfc->pAddressListDesc, &IndicationBuffer->InfoBuffer.AddrListDesc, l ); if (NO_ERROR != GetInterfaceIndex(pTcIfc->pAddressListDesc, &pTcIfc->InterfaceIndex, &pTcIfc->SpecificLinkCtx)) { pTcIfc->InterfaceIndex = IF_UNKNOWN; pTcIfc->SpecificLinkCtx = IF_UNKNOWN; } // // // Add the structure to the global linked list // GetLock(pTcIfc->Lock); SET_STATE(pTcIfc->State, OPEN); FreeLock(pTcIfc->Lock); GetLock( pGlobals->Lock ); InsertTailList(&pGlobals->TcIfcList, &pTcIfc->Linkage ); FreeLock( pGlobals->Lock ); #if 0 // // there's a new TC inetrface, check the GPC client list // OpenGpcClients(pTcIfc); #endif } else { Status = ERROR_NOT_ENOUGH_MEMORY; } break; case TC_NOTIFY_IFC_CLOSE: pTcIfc = GetTcIfc(InstanceName); REFDEL(&pTcIfc->RefCount, 'KIFC'); break; case TC_NOTIFY_IFC_CHANGE: pTcIfc = GetTcIfc(InstanceName); if (pTcIfc == NULL) { return Status; } // // copy the instance ID string data // pTcIfc->InstanceIDLength = IndicationBuffer->InfoBuffer.InstanceIDLength; memcpy(pTcIfc->InstanceID, IndicationBuffer->InfoBuffer.InstanceID, pTcIfc->InstanceIDLength); pTcIfc->InstanceID[pTcIfc->InstanceIDLength/sizeof(WCHAR)] = L'\0'; l = IndicationBufferSize - FIELD_OFFSET(TC_INDICATION_BUFFER,InfoBuffer) - FIELD_OFFSET(TC_SUPPORTED_INFO_BUFFER, AddrListDesc); AllocMem(&pAddrListDesc, l); if (pAddrListDesc) { // // copy the instance data // in this case - the network address // RtlCopyMemory( pAddrListDesc, &IndicationBuffer->InfoBuffer.AddrListDesc, l ); GetLock( pGlobals->Lock ); FreeMem(pTcIfc->pAddressListDesc); pTcIfc->AddrListBytesCount = l; pTcIfc->pAddressListDesc = pAddrListDesc; if (NO_ERROR != GetInterfaceIndex(pTcIfc->pAddressListDesc, &pTcIfc->InterfaceIndex, &pTcIfc->SpecificLinkCtx)) { pTcIfc->InterfaceIndex = IF_UNKNOWN; pTcIfc->SpecificLinkCtx = IF_UNKNOWN; } FreeLock( pGlobals->Lock ); #if 0 // // there's a new addr list, check the GPC client list // OpenGpcClients(pTcIfc); #endif } else { Status = ERROR_NOT_ENOUGH_MEMORY; } break; default: ASSERT(0); } return Status; } DWORD CreateClientStruc( IN HANDLE ClRegCtx, OUT PCLIENT_STRUC *ppClient ) { PCLIENT_STRUC pClient; DWORD Status = NO_ERROR; AllocMem(&pClient, sizeof(CLIENT_STRUC)); if (pClient != NULL) { RtlZeroMemory(pClient, sizeof(CLIENT_STRUC)); // // acquire a new handle for the client // pClient->ClHandle = AllocateHandle((PVOID)pClient); if (!pClient->ClHandle) { FreeMem(pClient); return ERROR_NOT_ENOUGH_MEMORY; } // // set the other parameters in the client interface // pClient->ObjectType = ENUM_CLIENT_TYPE; pClient->ClRegCtx = ClRegCtx; InitializeListHead(&pClient->InterfaceList); ReferenceInit(&pClient->RefCount, pClient, DereferenceClient); REFADD(&pClient->RefCount, 'CLNT'); __try { InitLock(pClient->Lock); } __except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); IF_DEBUG(ERRORS) { WSPRINT(("TcRegisterClient: Exception Error: = 0x%X\n", Status )); } FreeHandle(pClient->ClHandle); FreeMem(pClient); return Status; } SET_STATE(pClient->State, INSTALLING); } else { Status = ERROR_NOT_ENOUGH_MEMORY; } *ppClient = pClient; return Status; } DWORD CreateClInterfaceStruc( IN HANDLE ClIfcCtx, OUT PINTERFACE_STRUC *ppClIfc ) { PINTERFACE_STRUC pClIfc; DWORD Status = NO_ERROR; AllocMem(&pClIfc, sizeof(INTERFACE_STRUC)); if (pClIfc != NULL) { RtlZeroMemory(pClIfc, sizeof(INTERFACE_STRUC)); // // acquire a new handle for the client // GetLock(pGlobals->Lock); pClIfc->ClHandle = AllocateHandle((PVOID)pClIfc); FreeLock(pGlobals->Lock); if (!pClIfc->ClHandle) { FreeMem(pClIfc); return ERROR_NOT_ENOUGH_MEMORY; } if ((pClIfc->IfcEvent = CreateEvent( NULL, // pointer to security attributes TRUE, // flag for manual-reset event FALSE, // flag for initial state NULL // pointer to event-object name); )) == NULL) { Status = GetLastError(); IF_DEBUG(ERRORS) { WSPRINT(( "Error Creating Event for Interface: 0x%X:%d\n", pClIfc, Status)); } FreeHandle(pClIfc->ClHandle); FreeMem(pClIfc); return Status; } // // set the other parameters in the client interface // pClIfc->ObjectType = ENUM_INTERFACE_TYPE; pClIfc->ClIfcCtx = ClIfcCtx; pClIfc->CallbackThreadId = 0; ReferenceInit(&pClIfc->RefCount, pClIfc, DereferenceInterface); REFADD(&pClIfc->RefCount, 'CIFC'); InitializeListHead(&pClIfc->FlowList); __try { InitLock(pClIfc->Lock); } __except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); IF_DEBUG(ERRORS) { WSPRINT(("TcRegisterClient: Exception Error: = 0x%X\n", Status )); } CloseHandle(pClIfc->IfcEvent); FreeHandle(pClIfc->ClHandle); FreeMem(pClIfc); return Status; } SET_STATE(pClIfc->State, INSTALLING); pClIfc->Flags = 0; // reset flags } else { Status = ERROR_NOT_ENOUGH_MEMORY; } *ppClIfc = pClIfc; return Status; } DWORD CreateKernelInterfaceStruc( OUT PTC_IFC *ppTcIfc, IN DWORD AddressLength ) { PTC_IFC pTcIfc; DWORD Status = NO_ERROR; IF_DEBUG(CALLS) { WSPRINT(("==> CreateKernelInterfaceStruc: AddressLength %d\n", AddressLength)); } *ppTcIfc = NULL; AllocMem(&pTcIfc, sizeof(TC_IFC)); if (pTcIfc) { RtlZeroMemory(pTcIfc, sizeof(TC_IFC)); AllocMem(&pTcIfc->pAddressListDesc, AddressLength); if (pTcIfc->pAddressListDesc) { RtlZeroMemory(pTcIfc->pAddressListDesc, AddressLength); // // initialize the new structure // ReferenceInit(&pTcIfc->RefCount, pTcIfc, DereferenceKernelInterface); REFADD(&pTcIfc->RefCount, 'KIFC'); SET_STATE(pTcIfc->State, INSTALLING); __try { InitLock(pTcIfc->Lock); } __except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); IF_DEBUG(ERRORS) { WSPRINT(("TcRegisterClient: Exception Error: = 0x%X\n", Status )); } FreeMem(pTcIfc->pAddressListDesc); FreeMem(pTcIfc); return Status; } InitializeListHead(&pTcIfc->ClIfcList); } else { FreeMem(pTcIfc); Status = ERROR_NOT_ENOUGH_MEMORY; return Status; } } else { Status = ERROR_NOT_ENOUGH_MEMORY; return Status; } *ppTcIfc = pTcIfc; IF_DEBUG(CALLS) { WSPRINT(("==> CreateKernelInterfaceStruc: Status%d\n", Status)); } return Status; } DWORD DereferenceKernelInterface( PTC_IFC pTcIfc ) { DWORD Status = NO_ERROR; IF_DEBUG(CALLS) { WSPRINT(("==> DereferenceKernelInterfaceStruc: %X\n", pTcIfc)); } ASSERT(pTcIfc); ASSERT( IsListEmpty( &pTcIfc->ClIfcList ) ); GetLock( pGlobals->Lock ); RemoveEntryList(&pTcIfc->Linkage); FreeLock( pGlobals->Lock ); DeleteLock(pTcIfc->Lock); FreeMem(pTcIfc->pAddressListDesc); FreeMem(pTcIfc); IF_DEBUG(CALLS) { WSPRINT(("==> DereferenceKernelInterfaceStruc: %d\n", Status)); } return Status; } DWORD CreateFlowStruc( IN HANDLE ClFlowCtx, IN PTC_GEN_FLOW pGenFlow, OUT PFLOW_STRUC *ppFlow ) { PFLOW_STRUC pFlow; DWORD Status = NO_ERROR; ULONG l; PUCHAR pCurrentObject; LONG BufRemaining; *ppFlow = NULL; __try { pCurrentObject = (PUCHAR) pGenFlow->TcObjects; BufRemaining = pGenFlow->TcObjectsLength; while ((BufRemaining > 0) && (((QOS_OBJECT_HDR*)pCurrentObject)->ObjectType != QOS_OBJECT_END_OF_LIST)) { BufRemaining -= ((QOS_OBJECT_HDR*)pCurrentObject)->ObjectLength; pCurrentObject = pCurrentObject + ((QOS_OBJECT_HDR*)pCurrentObject)->ObjectLength; } if (BufRemaining < 0) return (ERROR_TC_OBJECT_LENGTH_INVALID); l = FIELD_OFFSET(TC_GEN_FLOW, TcObjects) + pGenFlow->TcObjectsLength; } __except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); IF_DEBUG(ERRORS) { WSPRINT(("CreateFlowStruc: Invalid pGenFlow: = 0x%X\n", Status )); } return Status; } AllocMem(&pFlow, sizeof(FLOW_STRUC)); if (pFlow != NULL) { RtlZeroMemory(pFlow, sizeof(FLOW_STRUC)); // // acquire a new handle for the flow // pFlow->ClHandle = AllocateHandle((PVOID)pFlow); if (!pFlow->ClHandle) { FreeMem(pFlow); return ERROR_NOT_ENOUGH_MEMORY; } // // Allocate memory and save the generic flow structure // AllocMem(&pFlow->pGenFlow, l); if (pFlow->pGenFlow == NULL) { FreeHandle(pFlow->ClHandle); FreeMem(pFlow); pFlow = NULL; Status = ERROR_NOT_ENOUGH_MEMORY; } else { // // copy the generic flow into the new allocation // __try { RtlCopyMemory(pFlow->pGenFlow, pGenFlow, l); } __except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); IF_DEBUG(ERRORS) { WSPRINT(("CreateFlowStruc: Exception Error: = 0x%X\n", Status )); } FreeMem(pFlow->pGenFlow); FreeHandle(pFlow->ClHandle); FreeMem(pFlow); return Status; } // // set the other parameters in the flow // pFlow->GenFlowLen = l; pFlow->ObjectType = ENUM_GEN_FLOW_TYPE; pFlow->ClFlowCtx = ClFlowCtx; pFlow->Flags = 0; pFlow->InstanceNameLength = 0; ReferenceInit(&pFlow->RefCount, pFlow, DereferenceFlow); REFADD(&pFlow->RefCount, 'FLOW'); pFlow->FilterCount = 0; InitializeListHead(&pFlow->FilterList); __try { InitLock(pFlow->Lock); } __except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); IF_DEBUG(ERRORS) { WSPRINT(("TcRegisterClient: Exception Error: = 0x%X\n", Status )); } FreeHandle(pFlow->ClHandle); FreeMem(pFlow->pGenFlow); FreeMem(pFlow); return Status; } SET_STATE(pFlow->State, INSTALLING); // // Next create the event // pFlow->PendingEvent = CreateEvent(NULL, // default attr FALSE, // auto reset FALSE, // init = not signaled NULL // no name ); if (!pFlow->PendingEvent) { // Failed to create event, get the error and free flow Status = GetLastError(); DeleteFlowStruc( pFlow ); return Status; } } } else { Status = ERROR_NOT_ENOUGH_MEMORY; } *ppFlow = pFlow; return Status; } DWORD CreateFilterStruc( IN PTC_GEN_FILTER pGenFilter, IN PFLOW_STRUC pFlow, OUT PFILTER_STRUC *ppFilter ) { PFILTER_STRUC pFilter; DWORD Status = NO_ERROR; ULONG GenFilterSize; PTC_GEN_FILTER pGpcFilter; PUCHAR p; ULONG ProtocolId; ULONG PatternSize; PIP_PATTERN pIpPattern; PTC_IFC pTcIfc; int i,n; *ppFilter = NULL; pTcIfc = pFlow->pInterface->pTcIfc; ASSERT(pTcIfc); __try { switch (pGenFilter->AddressType) { case NDIS_PROTOCOL_ID_TCP_IP: ProtocolId = GPC_PROTOCOL_TEMPLATE_IP; PatternSize = sizeof(IP_PATTERN); break; default: return ERROR_INVALID_ADDRESS_TYPE; } if (PatternSize != pGenFilter->PatternSize || pGenFilter->Pattern == NULL || pGenFilter->Mask == NULL) { return ERROR_INVALID_PARAMETER; } } __except(EXCEPTION_EXECUTE_HANDLER) { Status = ERROR_INVALID_PARAMETER; IF_DEBUG(ERRORS) { WSPRINT(("CreateFilterStruc: Exception Error: = 0x%X\n", Status )); } return Status; } AllocMem(&pFilter, sizeof(FILTER_STRUC)); if (pFilter != NULL) { RtlZeroMemory(pFilter, sizeof(FILTER_STRUC)); // // Allocate memory and save the generic filter structure // GenFilterSize = sizeof(TC_GEN_FILTER) + 2*pGenFilter->PatternSize; AllocMem(&pGpcFilter, GenFilterSize); if (pGpcFilter == NULL) { FreeMem(pFilter); pFilter = NULL; Status = ERROR_NOT_ENOUGH_MEMORY; } else { // // copy the generic filter to local storage // pGpcFilter->AddressType = pGenFilter->AddressType; pGpcFilter->PatternSize = PatternSize; p = (PUCHAR)pGpcFilter + sizeof(TC_GEN_FILTER); __try { RtlCopyMemory(p, pGenFilter->Pattern, pGenFilter->PatternSize); if (pGenFilter->AddressType == NDIS_PROTOCOL_ID_TCP_IP) { if(pTcIfc->InterfaceIndex == IF_UNKNOWN) { if (NO_ERROR != (Status = GetInterfaceIndex(pTcIfc->pAddressListDesc, &pTcIfc->InterfaceIndex, &pTcIfc->SpecificLinkCtx))) { FreeMem(pFilter); FreeMem(pGpcFilter); return Status; } } // // IP pattern, set reserved fields // pIpPattern = (PIP_PATTERN)p; pIpPattern->Reserved1 = pFlow->pInterface->pTcIfc->InterfaceIndex; pIpPattern->Reserved2 = pFlow->pInterface->pTcIfc->SpecificLinkCtx; pIpPattern->Reserved3[0] = pIpPattern->Reserved3[1] = pIpPattern->Reserved3[2] = 0; } } __except (EXCEPTION_EXECUTE_HANDLER) { Status = ERROR_INVALID_PARAMETER; IF_DEBUG(ERRORS) { WSPRINT(("CreateFilterStruc: Exception Error: = 0x%X\n", Status )); } FreeMem(pGpcFilter); FreeMem(pFilter); return Status; } pGpcFilter->Pattern = (PVOID)p; p += pGenFilter->PatternSize; __try { RtlCopyMemory(p, pGenFilter->Mask, pGenFilter->PatternSize); if (pGenFilter->AddressType == NDIS_PROTOCOL_ID_TCP_IP) { // // IP pattern, set reserved fields // pIpPattern = (PIP_PATTERN)p; pIpPattern->Reserved1 = pIpPattern->Reserved2 = 0xffffffff; pIpPattern->Reserved3[0] = pIpPattern->Reserved3[1] = pIpPattern->Reserved3[2] = 0xff; } } __except (EXCEPTION_EXECUTE_HANDLER) { Status = ERROR_INVALID_PARAMETER; IF_DEBUG(ERRORS) { WSPRINT(("CreateFilterStruc: Exception Error: = 0x%X\n", Status )); } FreeMem(pGpcFilter); FreeMem(pFilter); return Status; } pGpcFilter->Mask = (PVOID)p; pFilter->pGpcFilter = pGpcFilter; // // acquire a new handle for the Filter // pFilter->ClHandle = AllocateHandle((PVOID)pFilter); // what if we're out of memory? if (!pFilter->ClHandle) { IF_DEBUG(ERRORS) { WSPRINT(("CreateFilterStruc: Cant allocate Handle\n")); } FreeMem(pGpcFilter); FreeMem(pFilter); return ERROR_NOT_ENOUGH_MEMORY; } // // set the other parameters in the Filter // pFilter->ObjectType = ENUM_FILTER_TYPE; pFilter->Flags = 0; ReferenceInit(&pFilter->RefCount, pFilter, DereferenceFilter); REFADD(&pFilter->RefCount, 'FILT'); __try { InitLock(pFilter->Lock); } __except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); IF_DEBUG(ERRORS) { WSPRINT(("TcRegisterClient: Exception Error: = 0x%X\n", Status )); } FreeHandle(pFilter->ClHandle); FreeMem(pFilter); FreeMem(pGpcFilter); return Status; } SET_STATE(pFilter->State, INSTALLING); // // set the Gpc protocol template from the address type // pFilter->GpcProtocolTemplate = ProtocolId; } } else { Status = ERROR_NOT_ENOUGH_MEMORY; } *ppFilter = pFilter; return Status; } DWORD EnumAllInterfaces(VOID) { PCLIENT_STRUC pClient; DWORD Status; WMIHANDLE WmiHandle; ULONG MyBufferSize = 2 KiloBytes; // is this enough?!? PWNODE_ALL_DATA pWnode; PWNODE_ALL_DATA pWnodeBuffer; PTC_IFC pTcIfc; if (_init) return NO_ERROR; // // get a WMI block handle to the GUID_QOS_SUPPORTED // Status = WmiOpenBlock((GUID *)&GUID_QOS_TC_SUPPORTED, 0, &WmiHandle); if (ERROR_FAILED(Status)) { if (Status == ERROR_WMI_GUID_NOT_FOUND) { // // this means there is no TC data provider // Status = NO_ERROR; //ERROR_TC_NOT_SUPPORTED } return Status; } do { // // allocate a private buffer to retrieve all wnodes // AllocMem(&pWnodeBuffer, MyBufferSize); if (pWnodeBuffer == NULL) { WmiCloseBlock(WmiHandle); return ERROR_NOT_ENOUGH_MEMORY; } __try { Status = WmiQueryAllData(WmiHandle, &MyBufferSize, pWnodeBuffer); } __except (EXCEPTION_EXECUTE_HANDLER) { Status = GetExceptionCode(); IF_DEBUG(ERRORS) { WSPRINT(("EnumAllInterfaces: Exception Error: = %X\n", Status )); } } if (Status == ERROR_INSUFFICIENT_BUFFER) { // // failed since the buffer was too small // release the buffer and double the size // MyBufferSize *= 2; FreeMem(pWnodeBuffer); pWnodeBuffer = NULL; } } while (Status == ERROR_INSUFFICIENT_BUFFER); if (!ERROR_FAILED(Status)) { ULONG dwInstanceNum; ULONG InstanceSize; PULONG lpdwNameOffsets; BOOL bFixedSize = FALSE; USHORT usNameLength; ULONG DescSize; PTC_SUPPORTED_INFO_BUFFER pTcInfoBuffer; pWnode = pWnodeBuffer; ASSERT(pWnode->WnodeHeader.Flags & WNODE_FLAG_ALL_DATA); do { // // Check for fixed instance size // if (pWnode->WnodeHeader.Flags & WNODE_FLAG_FIXED_INSTANCE_SIZE) { InstanceSize = pWnode->FixedInstanceSize; bFixedSize = TRUE; pTcInfoBuffer = (PTC_SUPPORTED_INFO_BUFFER)OffsetToPtr(pWnode, pWnode->DataBlockOffset); } // // Get a pointer to the array of offsets to the instance names // lpdwNameOffsets = (PULONG) OffsetToPtr(pWnode, pWnode->OffsetInstanceNameOffsets); for ( dwInstanceNum = 0; dwInstanceNum < pWnode->InstanceCount; dwInstanceNum++) { usNameLength = *(USHORT *)OffsetToPtr(pWnode, lpdwNameOffsets[dwInstanceNum]); // // Length and offset for variable data // if ( !bFixedSize ) { InstanceSize = pWnode->OffsetInstanceDataAndLength[dwInstanceNum].LengthInstanceData; pTcInfoBuffer = (PTC_SUPPORTED_INFO_BUFFER)OffsetToPtr( (PBYTE)pWnode, pWnode->OffsetInstanceDataAndLength[dwInstanceNum].OffsetInstanceData); } // // we have all that is needed. we need to figure if // there is enough buffer space to put the data as well // ASSERT(usNameLength < MAX_STRING_LENGTH); DescSize = InstanceSize - FIELD_OFFSET(TC_SUPPORTED_INFO_BUFFER, AddrListDesc); // // Allocate a new interface descriptor structure // CreateKernelInterfaceStruc(&pTcIfc, DescSize); if (pTcIfc != NULL) { // // copy the instance name string data // RtlCopyMemory(pTcIfc->InstanceName, OffsetToPtr(pWnode, lpdwNameOffsets[dwInstanceNum]+2), usNameLength ); pTcIfc->InstanceNameLength = usNameLength; pTcIfc->InstanceName[usNameLength/sizeof(WCHAR)] = (WCHAR)0; // // copy the instance ID string data // RtlCopyMemory(pTcIfc->InstanceID, &pTcInfoBuffer->InstanceID[0], pTcInfoBuffer->InstanceIDLength ); pTcIfc->InstanceIDLength = pTcInfoBuffer->InstanceIDLength; pTcIfc->InstanceID[pTcInfoBuffer->InstanceIDLength/sizeof(WCHAR)] = (WCHAR)0; // // copy the instance data // in this case - the network address // pTcIfc->AddrListBytesCount = DescSize; // // a sizeof(ULONG) since the structure is defined as ARRAY // and the first ULONG is the number of elements // RtlCopyMemory( pTcIfc->pAddressListDesc, &pTcInfoBuffer->AddrListDesc, DescSize ); if (NO_ERROR != GetInterfaceIndex(pTcIfc->pAddressListDesc, &pTcIfc->InterfaceIndex, &pTcIfc->SpecificLinkCtx)) { pTcIfc->InterfaceIndex = IF_UNKNOWN; pTcIfc->SpecificLinkCtx = IF_UNKNOWN; } // set the state to open GetLock(pTcIfc->Lock); SET_STATE(pTcIfc->State, OPEN); FreeLock(pTcIfc->Lock); // // Add the structure to the global linked list // GetLock( pGlobals->Lock ); InsertTailList(&pGlobals->TcIfcList, &pTcIfc->Linkage ); FreeLock( pGlobals->Lock ); #if 0 // // make sure we have one gpc client per address type // Status = OpenGpcClients(pTcIfc); if (ERROR_FAILED(Status)) { break; } #endif } else { // // no more memory, quit here // Status = ERROR_NOT_ENOUGH_MEMORY; break; } } // // Update Wnode to point to next node // if ( pWnode->WnodeHeader.Linkage != 0) { pWnode = (PWNODE_ALL_DATA) OffsetToPtr( pWnode, pWnode->WnodeHeader.Linkage); } else { pWnode = NULL; } } while (pWnode != NULL && !ERROR_FAILED(Status)); } // // release resources and close WMI handle // WmiCloseBlock(WmiHandle); if (pWnodeBuffer) FreeMem(pWnodeBuffer); if (Status == NO_ERROR) { _init = TRUE; } return Status; } DWORD CloseInterface( IN PINTERFACE_STRUC pInterface, BOOLEAN RemoveFlows ) { IF_DEBUG(CALLS) { WSPRINT(("==>CloseInterface: pInterface=%X\n", pInterface)); } if (RemoveFlows) { CloseOpenFlows(pInterface); } REFDEL(&pInterface->RefCount, 'CIFC'); IF_DEBUG(CALLS) { WSPRINT(("==>CloseInterface: NO_ERROR\n")); } return NO_ERROR; } DWORD DeleteFlow( IN PFLOW_STRUC pFlow, IN BOOLEAN RemoveFilters ) { DWORD Status; PLIST_ENTRY pEntry; PFILTER_STRUC pFilter; IF_DEBUG(CALLS) { WSPRINT(("DeleteFlow: attempting to delete flow=0x%X\n", PtrToUlong(pFlow))); } if (RemoveFilters) { CloseOpenFilters(pFlow); } else { if (/*pFlow->FilterCount > 0*/ !IsListEmpty(&pFlow->FilterList)) { IF_DEBUG(ERRORS) { WSPRINT(("DeleteFlow: filter list NOT empty\n")); } #if DBG pEntry = pFlow->FilterList.Flink; while (pEntry != &pFlow->FilterList) { pFilter = CONTAINING_RECORD(pEntry, FILTER_STRUC, Linkage); IF_DEBUG(ERRORS) { WSPRINT(("<==TcDeleteFlow: Filter %x (handle %x) is open with RefCount:%d\n", pFilter, pFilter->ClHandle, pFilter->RefCount)); } pEntry = pEntry->Flink; } #endif return ERROR_TC_SUPPORTED_OBJECTS_EXIST; } } // // can remove the flow now // Status = IoDeleteFlow( pFlow, (BOOLEAN)!RemoveFilters ); IF_DEBUG(CALLS) { WSPRINT(("DeleteFlow: IoDeleteFlow returned=0x%X\n", Status)); } if (!ERROR_PENDING(Status)) { // // call completed, either success or failure... // CompleteDeleteFlow(pFlow, Status); } return Status; } DWORD DeleteFilter( IN PFILTER_STRUC pFilter ) { DWORD Status; IF_DEBUG(CALLS) { WSPRINT(( "DeleteFilter: attempting to delete=0x%X\n", PtrToUlong(pFilter))); } // // call to actually delete the filter // Status = IoDeleteFilter( pFilter ); IF_DEBUG(CALLS) { WSPRINT(( "DeleteFilter: IoDeleteFilter returned=0x%X\n", Status)); } //ASSERT(Status == NO_ERROR); REFDEL(&pFilter->RefCount, 'FILT'); return Status; } PGPC_CLIENT FindGpcClient( IN ULONG CfInfoType ) { PGPC_CLIENT pGpcClient = NULL; PLIST_ENTRY pHead, pEntry; GetLock( pGlobals->Lock ); pHead = &pGlobals->GpcClientList; pEntry = pHead->Flink; while (pHead != pEntry && pGpcClient == NULL) { pGpcClient = CONTAINING_RECORD(pEntry, GPC_CLIENT, Linkage); if (CfInfoType != pGpcClient->CfInfoType) { // // address type doesn't match! // pGpcClient = NULL; } pEntry = pEntry->Flink; } FreeLock( pGlobals->Lock ); return pGpcClient; } VOID CompleteAddFlow( IN PFLOW_STRUC pFlow, IN DWORD Status ) { PINTERFACE_STRUC pInterface; ASSERT(pFlow); ASSERT(!ERROR_PENDING(Status)); IF_DEBUG(CALLS) { WSPRINT(("CompleteAddFlow: pFlow=0x%X Status=0x%X\n", PtrToUlong(pFlow), Status)); } if(pFlow->CompletionBuffer) { FreeMem(pFlow->CompletionBuffer); pFlow->CompletionBuffer = NULL; } // // Check if the interface is still around. // GetLock(pFlow->Lock); pInterface = pFlow->pInterface; FreeLock(pFlow->Lock); if (ERROR_FAILED(Status)) { // // failed, release resources // CompleteDeleteFlow(pFlow, Status); } else { GetLock(pGlobals->Lock); GetLock(pInterface->Lock); if (QUERY_STATE(pInterface->State) != OPEN) { FreeLock(pInterface->Lock); FreeLock(pGlobals->Lock); IF_DEBUG(ERRORS) { WSPRINT(("CompleteAddFlow: Interface (%X) is NOT open pFlow=0x%X Status=0x%X\n", pInterface->ClHandle, PtrToUlong(pFlow), Status)); } // // Delete the only ref we have on this flow and get out. // REFDEL(&pFlow->RefCount, 'FLOW'); } else { FreeLock(pInterface->Lock); // // The flow is ready for business // GetLock(pFlow->Lock); SET_STATE(pFlow->State, OPEN); FreeLock(pFlow->Lock); // // Announce on the lists that we are ready for business // pInterface->FlowCount++; REFADD(&pInterface->RefCount, 'FLOW'); InsertTailList(&pInterface->FlowList, &pFlow->Linkage); FreeLock(pGlobals->Lock); } } // // This ref was taken in TcAddFlow. // REFDEL(&pInterface->RefCount, 'TCAF'); } VOID CompleteModifyFlow( IN PFLOW_STRUC pFlow, IN DWORD Status ) { ASSERT(pFlow); ASSERT(!ERROR_PENDING(Status)); IF_DEBUG(CALLS) { WSPRINT(("CompleteModifyFlow: pFlow=0x%X Status=0x%X\n", PtrToUlong(pFlow), Status)); } GetLock(pFlow->Lock); if(pFlow->CompletionBuffer) { FreeMem(pFlow->CompletionBuffer); pFlow->CompletionBuffer = NULL; } if (ERROR_FAILED(Status)) { // // failed, release the newly allocated generic flow parameters // FreeMem(pFlow->pGenFlow1); } else { // // modification accepted, update the generic flow parameters // FreeMem(pFlow->pGenFlow); pFlow->pGenFlow = pFlow->pGenFlow1; pFlow->GenFlowLen = pFlow->GenFlowLen; } // // clear the installing flag // pFlow->Flags &= ~TC_FLAGS_MODIFYING; pFlow->pGenFlow1 = NULL; pFlow->GenFlowLen1 = 0; FreeLock(pFlow->Lock); // // This ref was taken in TcModifyFlow // REFDEL(&pFlow->RefCount, 'TCMF'); IF_DEBUG(CALLS) { WSPRINT(("CompleteModifyFlow: pFlow=0x%X Status=0x%X\n", PtrToUlong(pFlow), Status)); } } VOID CompleteDeleteFlow( IN PFLOW_STRUC pFlow, IN DWORD Status ) { ASSERT(pFlow); //ASSERT(Status == NO_ERROR); //ASSERT(pFlow->CompletionBuffer); IF_DEBUG(CALLS) { WSPRINT(("CompleteDeleteFlow: pFlow=0x%X Status=0x%X\n", PtrToUlong(pFlow), Status)); } // // okay, release resources // GetLock(pFlow->Lock); if (pFlow->CompletionBuffer) { FreeMem(pFlow->CompletionBuffer); pFlow->CompletionBuffer = NULL; } FreeLock(pFlow->Lock); IF_DEBUG(REFCOUNTS) { WSPRINT(("#21 DEREF FLOW %X (%X) ref(%d)\n", pFlow->ClHandle, pFlow, pFlow->RefCount)); } REFDEL(&pFlow->RefCount, 'FLOW'); } DWORD OpenGpcClients( IN ULONG CfInfoType ) { DWORD Status = NO_ERROR; PLIST_ENTRY pHead, pEntry; PGPC_CLIENT pGpcClient; //int i; if (FindGpcClient(CfInfoType) == NULL) { // // create an entry in the // AllocMem(&pGpcClient, sizeof(GPC_CLIENT) ); if (pGpcClient == NULL) { return ERROR_NOT_ENOUGH_MEMORY; } pGpcClient->CfInfoType = CfInfoType; pGpcClient->RefCount = 1; // // register the gpc client // Status = IoRegisterClient(pGpcClient); if (ERROR_FAILED(Status)) { FreeMem(pGpcClient); } else { GetLock( pGlobals->Lock); InsertTailList(&pGlobals->GpcClientList, &pGpcClient->Linkage); FreeLock( pGlobals->Lock); } } return Status; } DWORD DereferenceInterface( IN PINTERFACE_STRUC pInterface ) { DWORD Status = NO_ERROR; IF_DEBUG(CALLS) { WSPRINT(("==>DereferenceInterface: IfcH=%X RefCount=%d\n", pInterface->ClHandle, pInterface->RefCount)); } FreeHandle(pInterface->ClHandle); //GetLock(pGlobals->Lock); IF_DEBUG(REFCOUNTS) { WSPRINT(("==>DereferenceInterface: IfcH=%X Interface=%x\n", pInterface->ClHandle, pInterface)); } // // close the interface and all flows/filters // RemoveEntryList(&pInterface->Linkage); RemoveEntryList(&pInterface->NextIfc); // // Deregister from any guid notification requests // TcipDeleteInterfaceFromNotificationList( pInterface, 0 ); // // #295267 // Do not dereference Client OR decrement Interface Count until // the Interface is actually going away. Otherwise, the client structures // are cleaned out, and when the ref count finally goes down and we // touch this code path, we hit an AV. // pInterface->pClient->InterfaceCount--; IF_DEBUG(HANDLES) { WSPRINT(("DEREF Client A : %x\n", pInterface->pClient->ClHandle)); } REFDEL(&pInterface->pClient->RefCount, 'CIFC'); REFDEL(&pInterface->pTcIfc->RefCount, 'CIFC'); // // This is complex, so read carefully. // We want CloseInterface to wait until the event is set (292120). // It is likely that in case the TcCloseInterface call didn't // come in, we dont have to set the Event since the TC_FLAGS_WAITING // will not be set in that case. // if (!IS_WAITING(pInterface->Flags)) { CloseHandle(pInterface->IfcEvent); } else { SetEvent(pInterface->IfcEvent); } // // free the interface resources // DeleteLock(pInterface->Lock); FreeMem(pInterface); //FreeLock(pGlobals->Lock); IF_DEBUG(CALLS) { WSPRINT(("<==DereferenceInterface: Status=%X\n", Status)); } return Status; } DWORD DereferenceFlow( IN PFLOW_STRUC pFlow ) { DWORD Status = NO_ERROR; IF_DEBUG(CALLS) { WSPRINT(("==>DereferenceFlow: FlowH=%X Flow=%X\n", pFlow->ClHandle, pFlow)); } //GetLock(pGlobals->Lock); IF_DEBUG(REFCOUNTS) { WSPRINT(("==>DereferenceFlow: FlowH=%X Flow=%X\n", pFlow->ClHandle, pFlow)); } FreeHandle(pFlow->ClHandle); GetLock(pFlow->Lock); if (QUERY_STATE(pFlow->State) != INSTALLING) { FreeLock(pFlow->Lock); RemoveEntryList(&pFlow->Linkage); pFlow->pInterface->FlowCount--; IF_DEBUG(HANDLES) { WSPRINT(("DEREF Interface A : %x\n", pFlow->pInterface->ClHandle)); } REFDEL(&pFlow->pInterface->RefCount, 'FLOW'); } else { FreeLock(pFlow->Lock); } // // moved here from CompleteDeleteFlow // // // free the interface resources // DeleteFlowStruc(pFlow); //FreeLock(pGlobals->Lock); IF_DEBUG(CALLS) { WSPRINT(("<==DereferenceFlow: Status=%X\n", Status)); } return Status; } DWORD DereferenceClient( IN PCLIENT_STRUC pClient ) { //GetLock( pGlobals->Lock ); IF_DEBUG(REFCOUNTS) { WSPRINT(("==>DereferenceClient: pClient=%x, Handle=%x, RefCount=%d\n", pClient, pClient->ClHandle, pClient->RefCount)); } GetLock(pClient->Lock); SET_STATE(pClient->State, REMOVED); FreeLock(pClient->Lock); FreeHandle( pClient->ClHandle ); RemoveEntryList( &pClient->Linkage ); DeleteLock(pClient->Lock); FreeMem( pClient ); //FreeLock( pGlobals->Lock ); return NO_ERROR; } DWORD DereferenceFilter( IN PFILTER_STRUC pFilter ) { DWORD Status = NO_ERROR; IF_DEBUG(CALLS) { WSPRINT(("==>DereferenceFilter: FilterH=%X RefCount=%d\n", pFilter->ClHandle, pFilter->RefCount)); } //GetLock(pGlobals->Lock); IF_DEBUG(REFCOUNTS) { WSPRINT(("==>DereferenceFilter: FilterH=%X Filter=%X on FLOW=%X\n", pFilter->ClHandle, pFilter, pFilter->pFlow)); } FreeHandle(pFilter->ClHandle); // // remove the flow from the list // GetLock(pFilter->Lock); if (QUERY_STATE(pFilter->State) != INSTALLING) { FreeLock(pFilter->Lock); RemoveEntryList(&pFilter->Linkage); pFilter->pFlow->FilterCount--; IF_DEBUG(REFCOUNTS) { WSPRINT(("#22 DEREF FLOW %X (%X) ref(%d)\n", pFilter->pFlow->ClHandle, pFilter->pFlow, pFilter->pFlow->RefCount)); } REFDEL(&pFilter->pFlow->RefCount, 'FILT'); } else { FreeLock(pFilter->Lock); } DeleteFilterStruc(pFilter); //FreeLock(pGlobals->Lock); IF_DEBUG(CALLS) { WSPRINT(("<==DereferenceFilter: Status=%X\n", Status)); } return Status; } DWORD GetInterfaceIndex( IN PADDRESS_LIST_DESCRIPTOR pAddressListDesc, OUT PULONG pInterfaceIndex, OUT PULONG pSpecificLinkCtx) { PNETWORK_ADDRESS_LIST pAddrList; NETWORK_ADDRESS UNALIGNED *pAddr; DWORD n,k; DWORD Status = NO_ERROR; PMIB_IPADDRTABLE pIpAddrTbl; DWORD dwSize = 2 KiloBytes; NETWORK_ADDRESS_IP UNALIGNED *pIpNetAddr = 0; DWORD cAddr; *pInterfaceIndex = 0; *pSpecificLinkCtx = 0; cAddr = pAddressListDesc->AddressList.AddressCount; if (cAddr == 0) { // // no address // return NO_ERROR; } #if INTERFACE_ID AllocMem(&pIpAddrTbl, dwSize); if (pIpAddrTbl == NULL) { return ERROR_NOT_ENOUGH_MEMORY; } pAddr = (UNALIGNED NETWORK_ADDRESS *) &pAddressListDesc->AddressList.Address[0]; for (n = 0; n < cAddr; n++) { if (pAddr->AddressType == NDIS_PROTOCOL_ID_TCP_IP) { pIpNetAddr = (UNALIGNED NETWORK_ADDRESS_IP *)&pAddr->Address[0]; break; } pAddr = (UNALIGNED NETWORK_ADDRESS *)(((PUCHAR)pAddr) + pAddr->AddressLength + FIELD_OFFSET(NETWORK_ADDRESS, Address)); } if (pIpNetAddr) { Status = GetIpAddrTableFromStack( pIpAddrTbl, dwSize, FALSE ); if (Status == NO_ERROR) { // // search for the matching IP address to IpAddr // in the table we got back from the stack // for (k = 0; k < pIpAddrTbl->dwNumEntries; k++) { if (pIpAddrTbl->table[k].dwAddr == pIpNetAddr->in_addr) { // // found one, get the index // *pInterfaceIndex = pIpAddrTbl->table[k].dwIndex; break; } } if (pAddressListDesc->MediaType == NdisMediumWan) { if (n+1 < cAddr) { // // there is another address that contains // the remote client address // this should be used as the link ID // pAddr = (UNALIGNED NETWORK_ADDRESS *)(((PUCHAR)pAddr) + pAddr->AddressLength + FIELD_OFFSET(NETWORK_ADDRESS, Address)); if (pAddr->AddressType == NDIS_PROTOCOL_ID_TCP_IP) { // // parse the second IP address, // this would be the remote IP address for dialin WAN // pIpNetAddr = (UNALIGNED NETWORK_ADDRESS_IP *)&pAddr->Address[0]; *pSpecificLinkCtx = pIpNetAddr->in_addr; } } } } } FreeMem(pIpAddrTbl); #endif return Status; }