diff options
author | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
---|---|---|
committer | Adam <you@example.com> | 2020-05-17 05:51:50 +0200 |
commit | e611b132f9b8abe35b362e5870b74bce94a1e58e (patch) | |
tree | a5781d2ec0e085eeca33cf350cf878f2efea6fe5 /private/ntos/tdi/tcpip/ip/ntip.c | |
download | NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.gz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.bz2 NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.lz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.xz NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.tar.zst NT4.0-e611b132f9b8abe35b362e5870b74bce94a1e58e.zip |
Diffstat (limited to '')
-rw-r--r-- | private/ntos/tdi/tcpip/ip/ntip.c | 3361 |
1 files changed, 3361 insertions, 0 deletions
diff --git a/private/ntos/tdi/tcpip/ip/ntip.c b/private/ntos/tdi/tcpip/ip/ntip.c new file mode 100644 index 000000000..040f025e3 --- /dev/null +++ b/private/ntos/tdi/tcpip/ip/ntip.c @@ -0,0 +1,3361 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + ntip.c + +Abstract: + + NT specific routines for loading and configuring the IP driver. + +Author: + + Mike Massa (mikemas) Aug 13, 1993 + +Revision History: + + Who When What + -------- -------- ---------------------------------------------- + mikemas 08-13-93 created + +Notes: + +--*/ + +#define _CTYPE_DISABLE_MACROS + +#include <oscfg.h> +#include <ndis.h> +#include <cxport.h> +#include <ip.h> +#include "ipdef.h" +#include "ipinit.h" +#include <ntddip.h> +#include <tdiinfo.h> +#include <ipinfo.h> + +// +// Debugging macros +// +#if DBG + +#define TCPTRACE(many_args) DbgPrint many_args + +#else // DBG + +#define TCPTRACE(many_args) DbgPrint many_args + +#endif // DBG + + +// +// definitions needed by inet_addr. +// +#define INADDR_NONE 0xffffffff +#define INADDR_ANY 0 +#define htonl(x) net_long(x) + +// +// Other local constants +// +#define WORK_BUFFER_SIZE 256 + +// +// Configuration defaults +// +#define DEFAULT_IGMP_LEVEL 2 +#define DEFAULT_IP_NETS 8 + + +// +// Local types +// +typedef struct _PerNetConfigInfo { + uint UseZeroBroadcast; + uint Mtu; + uint NumberOfGateways; + uint MaxForwardPending; // max routing packets pending +} PER_NET_CONFIG_INFO, *PPER_NET_CONFIG_INFO; + + +// +// Global variables. +// +PDRIVER_OBJECT IPDriverObject; +PDEVICE_OBJECT IPDeviceObject; +IPConfigInfo *IPConfiguration; +uint ArpUseEtherSnap = FALSE; +uint ArpAlwaysSourceRoute = FALSE; +uint IPAlwaysSourceRoute = TRUE; +uint ArpCacheLife = DEFAULT_ARP_CACHE_LIFE; +PWCHAR TempAdapterName; + +#ifndef _PNP_POWER + +NameMapping *AdptNameTable; +DriverRegMapping *DriverNameTable; +uint NumRegDrivers = 0; +uint NetConfigSize = DEFAULT_IP_NETS; + +#endif // _PNP_POWER + +// Used in the conversion of 100ns times to milliseconds. +static LARGE_INTEGER Magic10000 = {0xe219652c, 0xd1b71758}; + + +// +// External variables +// +extern LIST_ENTRY PendingEchoList; // def needed for initialization +extern LIST_ENTRY PendingIPSetNTEAddrList; // def needed for initialization +extern IPSNMPInfo IPSInfo; +EXTERNAL_LOCK(RouteTableLock) + +// +// Macros +// + +//++ +// +// LARGE_INTEGER +// CTEConvertMillisecondsTo100ns( +// IN LARGE_INTEGER MsTime +// ); +// +// Routine Description: +// +// Converts time expressed in hundreds of nanoseconds to milliseconds. +// +// Arguments: +// +// MsTime - Time in milliseconds. +// +// Return Value: +// +// Time in hundreds of nanoseconds. +// +//-- + +#define CTEConvertMillisecondsTo100ns(MsTime) \ + RtlExtendedIntegerMultiply(MsTime, 10000) + + +//++ +// +// LARGE_INTEGER +// CTEConvert100nsToMilliseconds( +// IN LARGE_INTEGER HnsTime +// ); +// +// Routine Description: +// +// Converts time expressed in hundreds of nanoseconds to milliseconds. +// +// Arguments: +// +// HnsTime - Time in hundreds of nanoseconds. +// +// Return Value: +// +// Time in milliseconds. +// +//-- + +#define SHIFT10000 13 +extern LARGE_INTEGER Magic10000; + +#define CTEConvert100nsToMilliseconds(HnsTime) \ + RtlExtendedMagicDivide((HnsTime), Magic10000, SHIFT10000) + + +// +// External function prototypes +// +extern int +IPInit( + void + ); + +long +IPSetInfo( + TDIObjectID *ID, + void *Buffer, + uint Size + ); + +NTSTATUS +IPDispatch( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ); + +NTSTATUS +OpenRegKey( + PHANDLE HandlePtr, + PWCHAR KeyName + ); + +NTSTATUS +GetRegDWORDValue( + HANDLE KeyHandle, + PWCHAR ValueName, + PULONG ValueData + ); + +NTSTATUS +SetRegDWORDValue( + HANDLE KeyHandle, + PWCHAR ValueName, + PULONG ValueData + ); + +NTSTATUS +GetRegSZValue( + HANDLE KeyHandle, + PWCHAR ValueName, + PUNICODE_STRING ValueData, + PULONG ValueType + ); + +NTSTATUS +GetRegMultiSZValue( + HANDLE KeyHandle, + PWCHAR ValueName, + PUNICODE_STRING ValueData + ); + +NTSTATUS +InitRegDWORDParameter( + HANDLE RegKey, + PWCHAR ValueName, + ULONG *Value, + ULONG DefaultValue + ); + +uint +RTReadNext( + void *Context, + void *Buffer + ); + +uint +RTValidateContext( + void *Context, + uint *Valid + ); + +// +// Local funcion prototypes +// +NTSTATUS +IPDriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ); + +NTSTATUS +IPProcessConfiguration( + VOID + ); + +NTSTATUS +IPProcessAdapterSection( + WCHAR *DeviceName, + WCHAR *AdapterName + ); + +#ifndef _PNP_POWER + +NTSTATUS +IPProcessIPAddressList( + HANDLE AdapterKey, + WCHAR *DeviceName, + WCHAR *AdapterName, + WCHAR *IpAddressList, + WCHAR *SubnetMaskList, + NDIS_STRING *LowerInterfaceString, + uint LowerInterfaceType, + PPER_NET_CONFIG_INFO PerNetConfigInfo + ); + +#else // _PNP_POWER + +uint +GetGeneralIFConfig( + IFGeneralConfig *ConfigInfo, + NDIS_HANDLE Handle + ); + +int +IsLLInterfaceValueNull( + NDIS_HANDLE Handle + ); + +IFAddrList * +GetIFAddrList( + UINT *NumAddr, + NDIS_HANDLE Handle + ); + +#endif // _PNP_POWER + +UINT +OpenIFConfig( + PNDIS_STRING ConfigName, + NDIS_HANDLE *Handle + ); + +VOID +CloseIFConfig( + NDIS_HANDLE Handle + ); + +IPConfigInfo * +IPGetConfig( + void + ); + +void +IPFreeConfig( + IPConfigInfo *ConfigInfo + ); + +ulong +GetGMTDelta( + void + ); + +ulong +GetTime( + void + ); + +BOOLEAN +IPConvertStringToAddress( + IN PWCHAR AddressString, + OUT PULONG IpAddress + ); + +uint +UseEtherSNAP( + PNDIS_STRING Name + ); + +void +GetAlwaysSourceRoute( + uint *pArpAlwaysSourceRoute, + uint *pIPAlwaysSourceRoute + ); + +uint +GetArpCacheLife( + void + ); + +ULONG +RouteMatch( + IN WCHAR *RouteString, + IN IPAddr Address, + IN IPMask Mask, + OUT IPAddr *DestVal, + OUT IPMask *DestMask, + OUT IPAddr *GateVal, + OUT ULONG *Metric + ); + +VOID +SetPersistentRoutesForNTE( + IPAddr Address, + IPMask Mask, + ULONG IFIndex + ); + +ULONG +GetCurrentRouteTable( + IPRouteEntry **ppRouteTable + ); + + +#ifdef ALLOC_PRAGMA + +#pragma alloc_text(INIT, IPDriverEntry) +#pragma alloc_text(INIT, IPProcessConfiguration) +#pragma alloc_text(INIT, IPProcessAdapterSection) +#pragma alloc_text(INIT, IPGetConfig) +#pragma alloc_text(INIT, IPFreeConfig) +#pragma alloc_text(INIT, GetGMTDelta) +#pragma alloc_text(INIT, GetTime) + +#ifndef _PNP_POWER + +#pragma alloc_text(INIT, IPProcessIPAddressList) +#pragma alloc_text(INIT, UseEtherSNAP) +#pragma alloc_text(INIT, GetAlwaysSourceRoute) +#pragma alloc_text(INIT, GetArpCacheLife) + +#else // _PNP_POWER + +#pragma alloc_text(PAGE, GetGeneralIFConfig) +#pragma alloc_text(PAGE, IsLLInterfaceValueNull) +#pragma alloc_text(PAGE, GetIFAddrList) +#pragma alloc_text(PAGE, UseEtherSNAP) +#pragma alloc_text(PAGE, GetAlwaysSourceRoute) +#pragma alloc_text(PAGE, GetArpCacheLife) + +#endif // _PNP_POWER + +#pragma alloc_text(PAGE, OpenIFConfig) +#pragma alloc_text(PAGE, CloseIFConfig) +#pragma alloc_text(PAGE, RouteMatch) +#pragma alloc_text(PAGE, SetPersistentRoutesForNTE) +#pragma alloc_text(PAGE, IPConvertStringToAddress) + +#endif // ALLOC_PRAGMA + +// +// Function definitions +// +NTSTATUS +IPDriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ) + +/*++ + +Routine Description: + + Initialization routine for the IP driver. + +Arguments: + + DriverObject - Pointer to the IP driver object created by the system. + DeviceDescription - The name of IP's node in the registry. + +Return Value: + + The final status from the initialization operation. + +--*/ + +{ + NTSTATUS status; + UNICODE_STRING deviceName; + + + IPDriverObject = DriverObject; + + // + // Create the device object. IoCreateDevice zeroes the memory + // occupied by the object. + // + + RtlInitUnicodeString(&deviceName, DD_IP_DEVICE_NAME); + + status = IoCreateDevice( + DriverObject, + 0, + &deviceName, + FILE_DEVICE_NETWORK, + 0, + FALSE, + &IPDeviceObject + ); + + if (!NT_SUCCESS(status)) { + TCPTRACE(( + "IP initialization failed: Unable to create device object %ws, status %lx.", + DD_IP_DEVICE_NAME, + status + )); + + CTELogEvent( + DriverObject, + EVENT_TCPIP_CREATE_DEVICE_FAILED, + 1, + 1, + &deviceName.Buffer, + 0, + NULL + ); + + return(status); + } + + // + // Intialize the device object. + // + IPDeviceObject->Flags |= DO_DIRECT_IO; + + // + // Initialize the list of pending echo request IRPs. + // + InitializeListHead(&PendingEchoList); + + // + // Initialize the list of pending SetAddr request IRPs. + // + InitializeListHead(&PendingIPSetNTEAddrList); + + // + // Finally, read our configuration parameters from the registry. + // + status = IPProcessConfiguration(); + + if (status != STATUS_SUCCESS) { + IoDeleteDevice(IPDeviceObject); + } + + return(status); +} + +NTSTATUS +IPProcessConfiguration( + VOID + ) + +/*++ + +Routine Description: + + Reads the IP configuration information from the registry and constructs + the configuration structure expected by the IP driver. + +Arguments: + + None. + +Return Value: + + STATUS_SUCCESS or an error status if an operation fails. + +--*/ + +{ + NTSTATUS status; + HANDLE myRegKey = NULL; + UNICODE_STRING bindString; + WCHAR *aName, + *endOfString; + WCHAR IPParametersRegistryKey[] = + L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Tcpip\\Parameters"; + WCHAR IPLinkageRegistryKey[] = + L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Tcpip\\Linkage"; + uint ArpTRSingleRoute; + + + bindString.Buffer = NULL; + + IPConfiguration = CTEAllocMem(sizeof(IPConfigInfo)); + + if (IPConfiguration == NULL) { + + CTELogEvent( + IPDriverObject, + EVENT_TCPIP_NO_RESOURCES_FOR_INIT, + 1, + 0, + NULL, + 0, + NULL + ); + + return(STATUS_INSUFFICIENT_RESOURCES); + } + + CTEMemSet(IPConfiguration, 0, sizeof(IPConfigInfo)); + +#ifndef _PNP_POWER + + IPConfiguration->ici_netinfo = CTEAllocMem( + sizeof(NetConfigInfo) * DEFAULT_IP_NETS + ); + + if (IPConfiguration->ici_netinfo == NULL) { + + CTEFreeMem(IPConfiguration); + + CTELogEvent( + IPDriverObject, + EVENT_TCPIP_NO_RESOURCES_FOR_INIT, + 2, + 0, + NULL, + 0, + NULL + ); + + return(STATUS_INSUFFICIENT_RESOURCES); + } + + CTEMemSet( + IPConfiguration->ici_netinfo, + 0, + sizeof(NetConfigInfo) * DEFAULT_IP_NETS + ); + +#endif // _PNP_POWER + + // + // Process the Ip\Parameters section of the registry + // + status = OpenRegKey(&myRegKey, IPParametersRegistryKey); + + if (NT_SUCCESS(status)) { + // + // Expected configuration values. We use reasonable defaults if they + // aren't available for some reason. + // + status = GetRegDWORDValue( + myRegKey, + L"IpEnableRouter", + &(IPConfiguration->ici_gateway) + ); + + if (!NT_SUCCESS(status)) { + TCPTRACE(( + "IP: Unable to read IpEnableRouter value from the registry.\n" + " Routing will be disabled.\n" + )); + IPConfiguration->ici_gateway = 0; + } + + // + // Optional (hidden) values + // + (VOID)InitRegDWORDParameter( + myRegKey, + L"ForwardBufferMemory", + &(IPConfiguration->ici_fwbufsize), + DEFAULT_FW_BUFSIZE + ); + + (VOID)InitRegDWORDParameter( + myRegKey, + L"MaxForwardBufferMemory", + &(IPConfiguration->ici_maxfwbufsize), + DEFAULT_MAX_FW_BUFSIZE + ); + + (VOID)InitRegDWORDParameter( + myRegKey, + L"ForwardBroadcasts", + &(IPConfiguration->ici_fwbcast), + FALSE + ); + + (VOID)InitRegDWORDParameter( + myRegKey, + L"NumForwardPackets", + &(IPConfiguration->ici_fwpackets), + DEFAULT_FW_PACKETS + ); + + (VOID)InitRegDWORDParameter( + myRegKey, + L"MaxNumForwardPackets", + &(IPConfiguration->ici_maxfwpackets), + DEFAULT_MAX_FW_PACKETS + ); + + (VOID)InitRegDWORDParameter( + myRegKey, + L"IGMPLevel", + &(IPConfiguration->ici_igmplevel), + DEFAULT_IGMP_LEVEL + ); + + (VOID)InitRegDWORDParameter( + myRegKey, + L"EnableDeadGWDetect", + &(IPConfiguration->ici_deadgwdetect), + TRUE + ); + + (VOID)InitRegDWORDParameter( + myRegKey, + L"EnablePMTUDiscovery", + &(IPConfiguration->ici_pmtudiscovery), + TRUE + ); + + (VOID)InitRegDWORDParameter( + myRegKey, + L"DefaultTTL", + &(IPConfiguration->ici_ttl), + DEFAULT_TTL + ); + + (VOID)InitRegDWORDParameter( + myRegKey, + L"DefaultTOS", + &(IPConfiguration->ici_tos), + DEFAULT_TOS + ); + + (VOID)InitRegDWORDParameter( + myRegKey, + L"ArpUseEtherSnap", + &ArpUseEtherSnap, + FALSE + ); + + // + // we check for the return status here because if this parameter was + // not defined, then we want the default behavior for both arp + // and ip broadcasts. For arp, the behavior is to not source route + // and source router alternately. For ip, it is to always source + // route. If the parameter is defined and is 0, then for arp the + // behavior does not change. For ip however, we do not source route + // at all. Ofcourse, when the parameter is set to a non-zero value, + // we always source route for both. + // + status = InitRegDWORDParameter( + myRegKey, + L"ArpAlwaysSourceRoute", + &ArpAlwaysSourceRoute, + FALSE + ); + + if (NT_SUCCESS(status)) + { + IPAlwaysSourceRoute = ArpAlwaysSourceRoute; + } + (VOID)InitRegDWORDParameter( + myRegKey, + L"ArpTRSingleRoute", + &ArpTRSingleRoute, + FALSE + ); + + if (ArpTRSingleRoute) { + TrRii = TR_RII_SINGLE; + } else { + TrRii = TR_RII_ALL; + } + + (VOID)InitRegDWORDParameter( + myRegKey, + L"ArpCacheLife", + &ArpCacheLife, + DEFAULT_ARP_CACHE_LIFE + ); + + ZwClose(myRegKey); + myRegKey = NULL; + } + else { + // + // Use reasonable defaults. + // + IPConfiguration->ici_fwbcast = 0; + IPConfiguration->ici_gateway = 0; + IPConfiguration->ici_fwbufsize = DEFAULT_FW_BUFSIZE; + IPConfiguration->ici_fwpackets = DEFAULT_FW_PACKETS; + IPConfiguration->ici_maxfwbufsize = DEFAULT_MAX_FW_BUFSIZE; + IPConfiguration->ici_maxfwpackets = DEFAULT_MAX_FW_PACKETS; + IPConfiguration->ici_igmplevel = DEFAULT_IGMP_LEVEL; + IPConfiguration->ici_deadgwdetect = FALSE; + IPConfiguration->ici_pmtudiscovery = FALSE; + IPConfiguration->ici_ttl = DEFAULT_TTL; + IPConfiguration->ici_tos = DEFAULT_TOS; + + TCPTRACE(( + "IP: Unable to open Tcpip\\Parameters registry key. Using defaults.\n" + )); + } + + + // + // Process the Ip\Linkage section of the registry + // + status = OpenRegKey(&myRegKey, IPLinkageRegistryKey); + + if (NT_SUCCESS(status)) { + + bindString.Buffer = CTEAllocMem(WORK_BUFFER_SIZE * sizeof(WCHAR)); + + if (bindString.Buffer == NULL) { + + CTELogEvent( + IPDriverObject, + EVENT_TCPIP_NO_RESOURCES_FOR_INIT, + 3, + 0, + NULL, + 0, + NULL + ); + + status = STATUS_INSUFFICIENT_RESOURCES; + goto error_exit; + } + + bindString.Buffer[0] = UNICODE_NULL; + bindString.Length = 0; + bindString.MaximumLength = WORK_BUFFER_SIZE * sizeof(WCHAR); + + status = GetRegMultiSZValue( + myRegKey, + L"Bind", + &bindString + ); + + if (NT_SUCCESS(status)) { + aName = bindString.Buffer; + + if (bindString.Length > 0) { + // + // bindString is a MULTI_SZ which is a series of strings separated + // by NULL's with a double NULL at the end. + // + while (*aName != UNICODE_NULL) { + PWCHAR deviceName; + + deviceName = aName; + + // + // Find the end of the current string in the MULTI_SZ. + // + while (*aName != UNICODE_NULL) { + aName++; + ASSERT( + aName < + (PWCHAR) ( ((PUCHAR)bindString.Buffer) + + bindString.MaximumLength + ) + ); + } + + endOfString = aName; + + // + // Backtrack to the first backslash. + // + while ((aName >= bindString.Buffer) && (*aName-- != L'\\')); + + aName += 2; + + status = IPProcessAdapterSection( + deviceName, + aName + ); + + aName = endOfString + 1; + } + } + } +#ifndef _PNP_POWER + else { + CTELogEvent( + IPDriverObject, + EVENT_TCPIP_NO_BINDINGS, + 1, + 0, + NULL, + 0, + NULL + ); + + TCPTRACE(( + "IP: Unable to open Tcpip\\Linkage\\Bind registry value.\n" + " Only the local loopback interface will be accessible.\n" + )); + + } +#endif _PNP_POWER + } + else { + CTELogEvent( + IPDriverObject, + EVENT_TCPIP_NO_BINDINGS, + 2, + 0, + NULL, + 0, + NULL + ); + + TCPTRACE(( + "IP: Unable to open registry key Tcpip\\Linkage.\n" + " Only the local loopback interface will be accessible.\n" + )); + } + + +#ifndef _PNP_POWER + + // + // Allocate the Driver and Adapter name tables + // + + DriverNameTable = (DriverRegMapping *) CTEAllocMem( + (IPConfiguration->ici_numnets + 1) * + sizeof(DriverRegMapping) + ); + + AdptNameTable = (NameMapping *) CTEAllocMem( + (IPConfiguration->ici_numnets + 1) * + sizeof(NameMapping) + ); + + if ((DriverNameTable != NULL) && (AdptNameTable != NULL)) { + CTEMemSet( + DriverNameTable, + 0, + sizeof(DriverRegMapping) * (IPConfiguration->ici_numnets + 1) + ); + CTEMemSet( + AdptNameTable, + 0, + sizeof(NameMapping) * (IPConfiguration->ici_numnets + 1) + ); + +#endif // _PNP_POWER + + if (!IPInit()) { + CTELogEvent( + IPDriverObject, + EVENT_TCPIP_IP_INIT_FAILED, + 1, + 0, + NULL, + 0, + NULL + ); + + TCPTRACE(("IP initialization failed.\n")); + status = STATUS_UNSUCCESSFUL; + } + else { + status = STATUS_SUCCESS; + } + +#ifndef _PNP_POWER + + } + else { + CTELogEvent( + IPDriverObject, + EVENT_TCPIP_IP_INIT_FAILED, + 1, + 0, + NULL, + 0, + NULL + ); + + TCPTRACE(("IP initialization failed.\n")); + status = STATUS_UNSUCCESSFUL; + } + +#endif // _PNP_POWER + +error_exit: + + if (bindString.Buffer != NULL) { + CTEFreeMem(bindString.Buffer); + } + +#ifndef _PNP_POWER + + if (AdptNameTable != NULL) { + CTEFreeMem(AdptNameTable); + } + + if (DriverNameTable != NULL) { + CTEFreeMem(DriverNameTable); + } + +#endif // _PNP_POWER + + if (myRegKey != NULL) { + ZwClose(myRegKey); + } + + if (IPConfiguration != NULL) { + IPFreeConfig(IPConfiguration); + } + + return(status); +} + + +NTSTATUS +IPProcessAdapterSection( + WCHAR *DeviceName, + WCHAR *AdapterName + ) + +/*++ + +Routine Description: + + Reads all of the information needed under the Parameters\TCPIP section + of an adapter to which IP is bound. + +Arguments: + + DeviceName - The name of the IP device. + AdapterName - The registry key for the adapter for this IP net. + +Return Value: + + STATUS_SUCCESS or an error status if an operation fails. + +--*/ + +{ + HANDLE myRegKey; + UNICODE_STRING valueString; + NTSTATUS status; + ULONG valueType; + ulong invalidNetContext = 0xFFFF; + WCHAR TcpipParametersKey[] = L"\\Parameters\\TCPIP"; + WCHAR ServicesRegistryKey[] = + L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"; +#ifndef _PNP_POWER + uint numberOfGateways = 0; + uint llInterfaceType; + WCHAR *ipAddressBuffer = NULL; + WCHAR *subnetMaskBuffer = NULL; + NDIS_STRING llInterfaceString; + PER_NET_CONFIG_INFO perNetConfigInfo; + NetConfigInfo *NetConfiguration; + PWCHAR temp; + + + RtlInitUnicodeString(&llInterfaceString, NULL); + + NetConfiguration = IPConfiguration->ici_netinfo + + IPConfiguration->ici_numnets; + +#endif // _PNP_POWER + + // + // Get the size of the AdapterName string the easy way. + // + RtlInitUnicodeString(&valueString, AdapterName); + + valueString.MaximumLength += sizeof(ServicesRegistryKey) + + sizeof(TcpipParametersKey); + + valueString.Buffer = CTEAllocMem(valueString.MaximumLength); + + if (valueString.Buffer == NULL) { + CTELogEvent( + IPDriverObject, + EVENT_TCPIP_NO_ADAPTER_RESOURCES, + 4, + 1, + &AdapterName, + 0, + NULL + ); + + TCPTRACE(("IP: Unable to allocate memory for reg key name\n")); + + return(STATUS_INSUFFICIENT_RESOURCES); + } + + valueString.Length = 0; + valueString.Buffer[0] = UNICODE_NULL; + + // + // Build the key name for the tcpip parameters section and open key. + // + status = RtlAppendUnicodeToString(&valueString, ServicesRegistryKey); + + if (!NT_SUCCESS(status)) { + CTELogEvent( + IPDriverObject, + EVENT_TCPIP_ADAPTER_REG_FAILURE, + 1, + 1, + &AdapterName, + 0, + NULL + ); + + TCPTRACE(("IP: Unable to append services name to key string\n")); + + goto exit2; + } + + status = RtlAppendUnicodeToString(&valueString, AdapterName); + + if (!NT_SUCCESS(status)) { + CTELogEvent( + IPDriverObject, + EVENT_TCPIP_ADAPTER_REG_FAILURE, + 2, + 1, + &AdapterName, + 0, + NULL + ); + + TCPTRACE(("IP: Unable to append adapter name to key string\n")); + + goto exit2; + } + + status = RtlAppendUnicodeToString(&valueString, TcpipParametersKey); + + if (!NT_SUCCESS(status)) { + CTELogEvent( + IPDriverObject, + EVENT_TCPIP_ADAPTER_REG_FAILURE, + 3, + 1, + &AdapterName, + 0, + NULL + ); + + TCPTRACE(("IP: Unable to append parameters name to key string\n")); + + goto exit2; + } + + status = OpenRegKey(&myRegKey, valueString.Buffer); + + if (!NT_SUCCESS(status)) { + CTELogEvent( + IPDriverObject, + EVENT_TCPIP_ADAPTER_REG_FAILURE, + 4, + 1, + &AdapterName, + 0, + NULL + ); + + TCPTRACE(( + "IP: Unable to open adapter registry key %ws\n", + valueString.Buffer + )); + + goto exit2; + } + + // + // Invalidate the interface context for DHCP. + // When the first net is successfully configured, we'll write in the + // proper values. + // + status = SetRegDWORDValue( + myRegKey, + L"IPInterfaceContext", + &(invalidNetContext) + ); + + if (!NT_SUCCESS(status)) { + CTELogEvent( + IPDriverObject, + EVENT_TCPIP_DHCP_INIT_FAILED, + 1, + 1, + &AdapterName, + 0, + NULL + ); + + TCPTRACE(( + "IP: Unable to Invalidate IPInterfaceContext value for adapter %ws.\n" + " DHCP may fail on this adapter.\n", + AdapterName + )); + + goto exit1; + } + +#ifndef _PNP_POWER + + // + // Process the gateway MultiSZ. The end is signified by a double NULL. + // This list currently only applies to the first IP address configured + // on this interface. + // + status = GetRegMultiSZValue( + myRegKey, + L"DefaultGateway", + &valueString + ); + + if (NT_SUCCESS(status)) { + PWCHAR addressString = valueString.Buffer; + + while (*addressString != UNICODE_NULL) { + IPAddr addressValue; + BOOLEAN conversionStatus; + + if (numberOfGateways >= MAX_DEFAULT_GWS) { + CTELogEvent( + IPDriverObject, + EVENT_TCPIP_TOO_MANY_GATEWAYS, + 1, + 1, + &AdapterName, + 0, + NULL + ); + + break; + } + + conversionStatus = IPConvertStringToAddress( + addressString, + &addressValue + ); + + if (conversionStatus && (addressValue != 0xFFFFFFFF)) { + if (addressValue != INADDR_ANY) { + NetConfiguration->nci_gw[numberOfGateways++] = addressValue; + } + } + else { + PWCHAR stringList[2]; + + stringList[0] = addressString; + stringList[1] = AdapterName; + + CTELogEvent( + IPDriverObject, + EVENT_TCPIP_INVALID_DEFAULT_GATEWAY, + 1, + 2, + stringList, + 0, + NULL + ); + + TCPTRACE(( + "IP: Invalid default gateway address %ws specified for adapter %ws.\n" + " Remote networks may not be reachable as a result.\n", + addressString, + AdapterName + )); + } + + // + // Walk over the entry we just processed. + // + while (*addressString++ != UNICODE_NULL); + } + } + else { + TCPTRACE(( + "IP: Unable to read DefaultGateway value for adapter %ws.\n" + " Initialization will continue.\n", + AdapterName + )); + } + + perNetConfigInfo.NumberOfGateways = numberOfGateways; + + // + // Figure out which lower layer driver to bind. + // + status = GetRegSZValue( + myRegKey, + L"LLInterface", + &valueString, + &valueType + ); + + if (NT_SUCCESS(status) && (*(valueString.Buffer) != UNICODE_NULL)) { + llInterfaceType = NET_TYPE_WAN; + + if (!CTEAllocateString( + &llInterfaceString, + CTELengthString(&valueString) + ) + ) { + CTELogEvent( + IPDriverObject, + EVENT_TCPIP_NO_ADAPTER_RESOURCES, + 1, + 1, + &AdapterName, + 0, + NULL + ); + + TCPTRACE(( + "IP initialization failure: Unable to allocate memory " + "for LLInterface string for adapter %ws.\n", + AdapterName + )); + status = STATUS_INSUFFICIENT_RESOURCES; + goto exit1; + } + + CTECopyString( + &llInterfaceString, + &valueString + ); + } + else { + // + // If the key isn't present or is empty, we use ARP + // + llInterfaceType = NET_TYPE_LAN; + } + + // + // Are we using zeros broadcasts? + // + status = GetRegDWORDValue( + myRegKey, + L"UseZeroBroadcast", + &(perNetConfigInfo.UseZeroBroadcast) + ); + + if (!NT_SUCCESS(status)) { + TCPTRACE(( + "IP: Unable to read UseZeroBroadcast value for adapter %ws.\n" + " All-nets broadcasts will be addressed to 255.255.255.255.\n", + AdapterName + )); + perNetConfigInfo.UseZeroBroadcast = FALSE; // default to off + } + + // + // Has anyone specified an MTU? + // + status = GetRegDWORDValue( + myRegKey, + L"MTU", + &(perNetConfigInfo.Mtu) + ); + + if (!NT_SUCCESS(status)) { + perNetConfigInfo.Mtu = 0xFFFFFFF; // The stack will pick one. + } + + // + // Have we been configured for more routing packets? + // + status = GetRegDWORDValue( + myRegKey, + L"MaxForwardPending", + &(perNetConfigInfo.MaxForwardPending) + ); + + if (!NT_SUCCESS(status)) { + perNetConfigInfo.MaxForwardPending = DEFAULT_MAX_PENDING; + } + + // + // Read the IP address and Subnet Mask lists + // + status = GetRegMultiSZValue( + myRegKey, + L"IpAddress", + &valueString + ); + + if (!NT_SUCCESS(status)) { + CTELogEvent( + IPDriverObject, + EVENT_TCPIP_NO_ADDRESS_LIST, + 1, + 1, + &AdapterName, + 0, + NULL + ); + + TCPTRACE(( + "IP: Unable to read the IP address list for adapter %ws.\n" + " IP will not be operational on this adapter\n", + AdapterName + )); + goto exit1; + } + + ipAddressBuffer = ExAllocatePool(NonPagedPool, valueString.Length); + + if (ipAddressBuffer == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + CTELogEvent( + IPDriverObject, + EVENT_TCPIP_NO_ADAPTER_RESOURCES, + 2, + 1, + &AdapterName, + 0, + NULL + ); + + TCPTRACE(("IP: Unable to allocate memory for IP address list\n")); + goto exit1; + } + + RtlCopyMemory(ipAddressBuffer, valueString.Buffer, valueString.Length); + + status = GetRegMultiSZValue( + myRegKey, + L"Subnetmask", + &valueString + ); + + if (!NT_SUCCESS(status)) { + CTELogEvent( + IPDriverObject, + EVENT_TCPIP_NO_MASK_LIST, + 1, + 1, + &AdapterName, + 0, + NULL + ); + + TCPTRACE(( + "IP: Unable to read the subnet mask list for adapter %ws.\n" + " IP will not be operational on this adapter.\n", + AdapterName + )); + goto exit1; + } + + subnetMaskBuffer = ExAllocatePool(NonPagedPool, valueString.Length); + + if (subnetMaskBuffer == NULL) { + status = STATUS_INSUFFICIENT_RESOURCES; + CTELogEvent( + IPDriverObject, + EVENT_TCPIP_NO_ADAPTER_RESOURCES, + 3, + 1, + &AdapterName, + 0, + NULL + ); + + TCPTRACE(("IP: Unable to allocate memory for subnet mask list\n")); + goto exit1; + } + + RtlCopyMemory(subnetMaskBuffer, valueString.Buffer, valueString.Length); + + // + // Initialize each net in the list + // + status = IPProcessIPAddressList( + myRegKey, + DeviceName, + AdapterName, + ipAddressBuffer, + subnetMaskBuffer, + &llInterfaceString, + llInterfaceType, + &perNetConfigInfo + ); + + if (status == STATUS_SUCCESS) { + // + // We leave the registry key open. It will be closed when + // initialization is completed. + // + goto exit2; + } + +#endif // ndef _PNP_POWER + + +exit1: + + ZwClose(myRegKey); + +exit2: + + if (valueString.Buffer != NULL) { + CTEFreeMem(valueString.Buffer); + } + +#ifndef _PNP_POWER + + if (ipAddressBuffer != NULL) { + ExFreePool(ipAddressBuffer); + } + + if (subnetMaskBuffer != NULL) { + ExFreePool(subnetMaskBuffer); + } + + if (llInterfaceString.Buffer != NULL) { + CTEFreeString(&llInterfaceString); + } + +#endif // _PNP_POWER + + return(status); +} + +#ifndef _PNP_POWER + +NTSTATUS +IPProcessIPAddressList( + HANDLE AdapterKey, + WCHAR *DeviceName, + WCHAR *AdapterName, + WCHAR *IpAddressList, + WCHAR *SubnetMaskList, + NDIS_STRING *LowerInterfaceString, + uint LowerInterfaceType, + PPER_NET_CONFIG_INFO PerNetConfigInfo + ) + +/*++ + +Routine Description: + + Processes the IP address string for an adapter and creates entries + in the IP configuration structure for each interface. + +Arguments: + + AdapterKey - The registry key for the adapter for this IP net. + DeviceName - The name of the IP device. + AdapterName - The name of the adapter being configured. + IpAddressList - The REG_MULTI_SZ list of IP address strings for + this adapter. + SubnetMaskList - The REG_MULTI_SZ list of subnet masks to match the + the addresses in IpAddressList. + LowerInterfaceString - The name of the link layer interface driver + supporting this adapter. + LowerInterfaceType - The type of link layer interface (LAN, WAN, etc). + PerNetConfigInfo - Miscellaneous information that applies to all + network interfaces on an adapter. + +Return Value: + + An error status if an error occurs which prevents configuration + from continuing, else STATUS_SUCCESS. Events will be logged for + non-fatal errors. + +--*/ + +{ + IPAddr addressValue; + BOOLEAN firstTime = TRUE; + BOOLEAN configuredOne = FALSE; + NetConfigInfo *NetConfiguration; + UNICODE_STRING adapterString; + UNICODE_STRING configString; + PWCHAR configName = L"\\Parameters\\Tcpip"; + + + while (*IpAddressList != UNICODE_NULL) { + BOOLEAN conversionStatus; + + + if (IPConfiguration->ici_numnets >= ((int) (NetConfigSize - 1))) { + NetConfigInfo *NewInfo; + + NewInfo = CTEAllocMem( + (NetConfigSize + DEFAULT_IP_NETS) * + sizeof(NetConfigInfo) + ); + + if (NewInfo == NULL) { + CTELogEvent( + IPDriverObject, + EVENT_TCPIP_TOO_MANY_NETS, + 1, + 1, + &AdapterName, + 0, + NULL + ); + + TCPTRACE(( + "IP: bound to too many nets. Further bindings, starting with\n" + " network %ws on adapter %ws cannot be made\n", + IpAddressList, + AdapterName + )); + + break; + } + + CTEMemCopy( + NewInfo, + IPConfiguration->ici_netinfo, + NetConfigSize * sizeof(NetConfigInfo) + ); + + CTEMemSet( + (NewInfo + NetConfigSize), + 0, + DEFAULT_IP_NETS + ); + + CTEFreeMem(IPConfiguration->ici_netinfo); + IPConfiguration->ici_netinfo = NewInfo; + NetConfigSize += DEFAULT_IP_NETS; + } + + NetConfiguration = IPConfiguration->ici_netinfo + + IPConfiguration->ici_numnets; + + if (*SubnetMaskList == UNICODE_NULL) { + PWCHAR stringList[2]; + + stringList[0] = IpAddressList; + stringList[1] = AdapterName; + + CTELogEvent( + IPDriverObject, + EVENT_TCPIP_NO_MASK, + 1, + 2, + stringList, + 0, + NULL + ); + + TCPTRACE(( + "IP: No subnet specified for IP address %ws and all\n" + " subsequent IP addresses on adapter %ws. These\n" + " interfaces will not be initialized.\n", + IpAddressList, + AdapterName + )); + + break; + } + + conversionStatus = IPConvertStringToAddress( + IpAddressList, + &addressValue + ); + + if (!conversionStatus || (addressValue == 0xFFFFFFFF)) { + PWCHAR stringList[2]; + + stringList[0] = IpAddressList; + stringList[1] = AdapterName; + + CTELogEvent( + IPDriverObject, + EVENT_TCPIP_INVALID_ADDRESS, + 1, + 2, + stringList, + 0, + NULL + ); + + TCPTRACE(( + "IP: Invalid IP address %ws specified for adapter %ws.\n" + " This interface will not be initialized.\n", + IpAddressList, + AdapterName + )); + firstTime = FALSE; + goto next_entry; + } + + NetConfiguration->nci_addr = addressValue; + + conversionStatus = IPConvertStringToAddress( + SubnetMaskList, + &addressValue + ); + + if (!conversionStatus || (addressValue == 0xFFFFFFFF)) { + PWCHAR stringList[3]; + + stringList[0] = SubnetMaskList; + stringList[1] = IpAddressList; + stringList[2] = AdapterName; + + CTELogEvent( + IPDriverObject, + EVENT_TCPIP_INVALID_MASK, + 1, + 3, + stringList, + 0, + NULL + ); + + TCPTRACE(( + "IP: Invalid subnet Mask %ws specified for IP address %ws " + "on adapter %ws\n" + " This interface will not be initialized\n", + SubnetMaskList, + IpAddressList, + AdapterName + )); + firstTime = FALSE; + goto next_entry; + } + + NetConfiguration->nci_mask = addressValue; + + NetConfiguration->nci_mtu = PerNetConfigInfo->Mtu; + NetConfiguration->nci_maxpending = PerNetConfigInfo->MaxForwardPending; + NetConfiguration->nci_zerobcast = PerNetConfigInfo->UseZeroBroadcast; + NetConfiguration->nci_type = LowerInterfaceType; + + NetConfiguration->nci_numgws = PerNetConfigInfo->NumberOfGateways; + PerNetConfigInfo->NumberOfGateways = 0; + // this only applies to the first interface. + + NetConfiguration->nci_type = LowerInterfaceType; + + RtlInitUnicodeString( + &(NetConfiguration->nci_name), + DeviceName + ); + + RtlInitUnicodeString(&configString, configName); + RtlInitUnicodeString(&adapterString, AdapterName); + + if (!CTEAllocateString( + &(NetConfiguration->nci_configname), + (adapterString.Length + configString.Length) + ) + ) + { + CTELogEvent( + IPDriverObject, + EVENT_TCPIP_NO_ADAPTER_RESOURCES, + 4, + 1, + &AdapterName, + 0, + NULL + ); + + TCPTRACE(( + "IP: Unable to allocate ConfigName string for interface\n" + " %ws on adapter %ws. This interface and all subsequent\n" + " interfaces on this adapter will be unavailable.\n", + IpAddressList, + AdapterName + )); + break; + } + + CTECopyString( + &(NetConfiguration->nci_configname), + &adapterString + ); + + RtlAppendUnicodeStringToString( + &(NetConfiguration->nci_configname), + &configString + ); + + if (LowerInterfaceType != NET_TYPE_LAN) { + + if (!CTEAllocateString( + &(NetConfiguration->nci_driver), + CTELengthString(LowerInterfaceString) + ) + ) { + CTELogEvent( + IPDriverObject, + EVENT_TCPIP_NO_ADAPTER_RESOURCES, + 4, + 1, + &AdapterName, + 0, + NULL + ); + + TCPTRACE(( + "IP: Unable to allocate LLInterface string for interface\n" + " %ws on adapter %ws. This interface and all subsequent\n" + " interfaces on this adapter will be unavailable.\n", + IpAddressList, + AdapterName + )); + break; + } + + CTECopyString( + &(NetConfiguration->nci_driver), + LowerInterfaceString + ); + } + else { + RtlInitUnicodeString(&(NetConfiguration->nci_driver), NULL); + } + + if (firstTime) { + firstTime = FALSE; + NetConfiguration->nci_reghandle = AdapterKey; + } + else { + NetConfiguration->nci_reghandle = NULL; + } + + IPConfiguration->ici_numnets++; + configuredOne = TRUE; + +next_entry: + + while(*IpAddressList++ != UNICODE_NULL); + while(*SubnetMaskList++ != UNICODE_NULL); + } + + if (configuredOne == FALSE) { + ZwClose(AdapterKey); + } + + return(STATUS_SUCCESS); +} + + +#else // ndef _PNP_POWER + + +uint +GetGeneralIFConfig( + IFGeneralConfig *ConfigInfo, + NDIS_HANDLE Handle + ) + +/*++ + + Routine Description: + + A routine to get the general per-interface config info, such as MTU, + type of broadcast, etc. The caller gives us a structure to be filled in + and a handle, and we fill in the structure if we can. + + Arguments: + ConfigInfo - Structure to be filled in. + Handle - Config handle from OpenIFConfig(). + + Return Value: + TRUE if we got all the required info, FALSE otherwise. + +--*/ + +{ + UNICODE_STRING valueString; + NTSTATUS status; + UINT numberOfGateways = 0; + UCHAR TempBuffer[WORK_BUFFER_SIZE]; + ULONG ulAddGateway,ulTemp; + + PAGED_CODE(); + + // + // Process the gateway MultiSZ. The end is signified by a double NULL. + // This list currently only applies to the first IP address configured + // on this interface. + // + + ConfigInfo->igc_numgws = 0; + + ulAddGateway = TRUE; + + CTEMemSet(ConfigInfo->igc_gw, 0, sizeof(IPAddr) * MAX_DEFAULT_GWS); + + valueString.Length = 0; + valueString.MaximumLength = WORK_BUFFER_SIZE; + valueString.Buffer = (PWCHAR)TempBuffer; + + ulTemp = 0; + + status = GetRegDWORDValue(Handle, + L"DontAddDefaultGateway", + &ulTemp); + + if(NT_SUCCESS(status)) + { + if(ulTemp == 1) + { + ulAddGateway = FALSE; + } + } + + if(ulAddGateway) + { + status = GetRegMultiSZValue( + Handle, + L"DefaultGateway", + &valueString + ); + + if (NT_SUCCESS(status)) { + PWCHAR addressString = valueString.Buffer; + + while (*addressString != UNICODE_NULL) { + IPAddr addressValue; + BOOLEAN conversionStatus; + + if (numberOfGateways >= MAX_DEFAULT_GWS) { + CTELogEvent( + IPDriverObject, + EVENT_TCPIP_TOO_MANY_GATEWAYS, + 1, + 1, + &TempAdapterName, + 0, + NULL + ); + + break; + } + + conversionStatus = IPConvertStringToAddress( + addressString, + &addressValue + ); + + if (conversionStatus && (addressValue != 0xFFFFFFFF)) { + if (addressValue != INADDR_ANY) { + ConfigInfo->igc_gw[numberOfGateways++] = addressValue; + } + } + else { + PWCHAR stringList[2]; + + stringList[0] = addressString; + stringList[1] = TempAdapterName; + + CTELogEvent( + IPDriverObject, + EVENT_TCPIP_INVALID_DEFAULT_GATEWAY, + 1, + 2, + stringList, + 0, + NULL + ); + + TCPTRACE(( + "IP: Invalid default gateway address %ws specified for adapter %ws.\n" + " Remote networks may not be reachable as a result.\n", + addressString, + TempAdapterName + )); + } + + // + // Walk over the entry we just processed. + // + while (*addressString++ != UNICODE_NULL); + } + } + else { + TCPTRACE(( + "IP: Unable to read DefaultGateway value for adapter %ws.\n" + " Initialization will continue.\n", + TempAdapterName + )); + } + + ConfigInfo->igc_numgws = numberOfGateways; + } + + // + // Are we using zeros broadcasts? + // + status = GetRegDWORDValue( + Handle, + L"UseZeroBroadcast", + &(ConfigInfo->igc_zerobcast) + ); + + if (!NT_SUCCESS(status)) { + TCPTRACE(( + "IP: Unable to read UseZeroBroadcast value for adapter %ws.\n" + " All-nets broadcasts will be addressed to 255.255.255.255.\n", + TempAdapterName + )); + ConfigInfo->igc_zerobcast = FALSE; // default to off + } + + // + // Has anyone specified an MTU? + // + status = GetRegDWORDValue( + Handle, + L"MTU", + &(ConfigInfo->igc_mtu) + ); + + if (!NT_SUCCESS(status)) { + ConfigInfo->igc_mtu = 0xFFFFFFF; // The stack will pick one. + } + + // + // Have we been configured for more routing packets? + // + status = GetRegDWORDValue( + Handle, + L"MaxForwardPending", + &(ConfigInfo->igc_maxpending) + ); + + if (!NT_SUCCESS(status)) { + ConfigInfo->igc_maxpending = DEFAULT_MAX_PENDING; + } + // + // Has Router Discovery been configured? + // + + status = GetRegDWORDValue( + Handle, + L"PerformRouterDiscovery", + &(ConfigInfo->igc_rtrdiscovery) + ); + + if (!NT_SUCCESS(status)) { + ConfigInfo->igc_rtrdiscovery = 1; + } + + // + // [BUGBUG] Only for 4.0 sp2 Turn off ICMP rtr discovery. + // + ConfigInfo->igc_rtrdiscovery = 0; + + // + // Has Router Discovery Address been configured? + // + + status = GetRegDWORDValue( + Handle, + L"SolicitationAddressBCast", + &ulTemp + ); + + if (!NT_SUCCESS(status)) { + ConfigInfo->igc_rtrdiscaddr = ALL_ROUTER_MCAST; + } else { + if (ulTemp == 1) { + ConfigInfo->igc_rtrdiscaddr = 0xffffffff; + } else { + ConfigInfo->igc_rtrdiscaddr = ALL_ROUTER_MCAST; + } + } + + return TRUE; +} + + +int +IsLLInterfaceValueNull( + NDIS_HANDLE Handle + ) +/*++ + + Routine Description: + + Called to see if the LLInterface value in the registry key for which the + handle is provided, is NULL or not. + + Arguments: + Handle - Handle to use for reading config. + + Return Value: + + FALSE if value is not null + TRUE if it is null + +--*/ +{ + UNICODE_STRING valueString ; + ULONG valueType ; + NTSTATUS status ; + + + PAGED_CODE(); + + valueString.MaximumLength = 200 ; + valueString.Buffer = CTEAllocMem(valueString.MaximumLength) ; + + status = GetRegSZValue( + Handle, + L"LLInterface", + &valueString, + &valueType + ); + + if (NT_SUCCESS(status) && (*(valueString.Buffer) != UNICODE_NULL)) { + CTEFreeMem (valueString.Buffer) ; + return FALSE ; + } else { + CTEFreeMem (valueString.Buffer) ; + return TRUE ; + } +} + + +IFAddrList * +GetIFAddrList( + UINT *NumAddr, + NDIS_HANDLE Handle + ) +/*++ + + Routine Description: + + Called to read the list of IF addresses and masks for an interface. + We'll get the address pointer first, then walk the list counting + to find out how many addresses we have. Then we allocate memory for the + list, and walk down the list converting them. After that we'll get + the mask list and convert it. + + Arguments: + NumAddr - Where to return number of address we have. + Handle - Handle to use for reading config. + + Return Value: + + Pointer to IF address list if we get one, or NULL otherwise. + +--*/ +{ + UNICODE_STRING ValueString; + NTSTATUS Status; + UINT AddressCount = 0; + UINT GoodAddresses = 0; + PWCHAR CurrentAddress; + PWCHAR CurrentMask; + PWCHAR AddressString; + PWCHAR MaskString; + IFAddrList *AddressList; + UINT i; + BOOLEAN ConversionStatus; + IPAddr AddressValue; + IPAddr MaskValue; + UCHAR TempBuffer[WORK_BUFFER_SIZE]; + + + PAGED_CODE(); + + ValueString.Length = 0; + ValueString.MaximumLength = WORK_BUFFER_SIZE; + ValueString.Buffer = (PWCHAR)CTEAllocMem(WORK_BUFFER_SIZE); + + if (ValueString.Buffer == NULL) { + CTELogEvent( + IPDriverObject, + EVENT_TCPIP_NO_ADAPTER_RESOURCES, + 2, + 1, + &TempAdapterName, + 0, + NULL + ); + + TCPTRACE(("IP: Unable to allocate memory for IP address list WB\n")); + return NULL; + } + + // First, try to read the IpAddress string. + + Status = GetRegMultiSZValue( + Handle, + L"IpAddress", + &ValueString + ); + + if (!NT_SUCCESS(Status)) { + CTELogEvent( + IPDriverObject, + EVENT_TCPIP_NO_ADDRESS_LIST, + 1, + 1, + &TempAdapterName, + 0, + NULL + ); + + TCPTRACE(( + "IP: Unable to read the IP address list for adapter %ws.\n" + " IP will not be operational on this adapter\n", + TempAdapterName + )); + ExFreePool(ValueString.Buffer); + return NULL; + } + + AddressString = ExAllocatePool(NonPagedPool, ValueString.MaximumLength); + + if (AddressString == NULL) { + CTELogEvent( + IPDriverObject, + EVENT_TCPIP_NO_ADAPTER_RESOURCES, + 2, + 1, + &TempAdapterName, + 0, + NULL + ); + + TCPTRACE(("IP: Unable to allocate memory for IP address list\n")); + ExFreePool(ValueString.Buffer); + return NULL; + } + + RtlCopyMemory(AddressString, ValueString.Buffer, ValueString.MaximumLength); + + Status = GetRegMultiSZValue( + Handle, + L"Subnetmask", + &ValueString + ); + + if (!NT_SUCCESS(Status)) { + CTELogEvent( + IPDriverObject, + EVENT_TCPIP_NO_MASK_LIST, + 1, + 1, + &TempAdapterName, + 0, + NULL + ); + + TCPTRACE(( + "IP: Unable to read the subnet mask list for adapter %ws.\n" + " IP will not be operational on this adapter.\n", + TempAdapterName + )); + + ExFreePool(AddressString); + ExFreePool(ValueString.Buffer); + return NULL; + } + + MaskString = ExAllocatePool(NonPagedPool, ValueString.MaximumLength); + + if (MaskString == NULL) { + CTELogEvent( + IPDriverObject, + EVENT_TCPIP_NO_ADAPTER_RESOURCES, + 3, + 1, + &TempAdapterName, + 0, + NULL + ); + + TCPTRACE(("IP: Unable to allocate memory for subnet mask list\n")); + ExFreePool(AddressString); + ExFreePool(ValueString.Buffer); + return NULL; + } + + RtlCopyMemory(MaskString, ValueString.Buffer, ValueString.MaximumLength); + + + CurrentAddress = AddressString; + CurrentMask = MaskString; + + while (*CurrentAddress != UNICODE_NULL && + *CurrentMask != UNICODE_NULL) { + + // We have a potential IP address. + + AddressCount++; + + // Skip this one. + while (*CurrentAddress++ != UNICODE_NULL); + while (*CurrentMask++ != UNICODE_NULL); + } + + if (AddressCount == 0) { + + ExFreePool(AddressString); + ExFreePool(MaskString); + ExFreePool(ValueString.Buffer); + return NULL; + } + + // Allocate memory. + AddressList = CTEAllocMem(sizeof(IFAddrList) * AddressCount); + + if (AddressList == NULL) { + CTELogEvent( + IPDriverObject, + EVENT_TCPIP_NO_ADAPTER_RESOURCES, + 2, + 1, + &TempAdapterName, + 0, + NULL + ); + + TCPTRACE(("IP: Unable to allocate memory for IP address list\n")); + ExFreePool(AddressString); + ExFreePool(MaskString); + ExFreePool(ValueString.Buffer); + return NULL; + } + + // Walk the list again, converting each address. + + CurrentAddress = AddressString; + CurrentMask = MaskString; + + for (i = 0; i < AddressCount; i++) { + ConversionStatus = IPConvertStringToAddress( + CurrentAddress, + &AddressValue + ); + + if (!ConversionStatus || (AddressValue == 0xFFFFFFFF)) { + PWCHAR stringList[2]; + + stringList[0] = CurrentAddress; + stringList[1] = TempAdapterName; + + CTELogEvent( + IPDriverObject, + EVENT_TCPIP_INVALID_ADDRESS, + 1, + 2, + stringList, + 0, + NULL + ); + + TCPTRACE(( + "IP: Invalid IP address %ws specified for adapter %ws.\n" + " This interface will not be initialized.\n", + CurrentAddress, + TempAdapterName + )); + + goto nextone; + + } + + // Now do the current mask. + + ConversionStatus = IPConvertStringToAddress( + CurrentMask, + &MaskValue + ); + + if (!ConversionStatus) { + PWCHAR stringList[3]; + + stringList[0] = CurrentMask; + stringList[1] = CurrentAddress; + stringList[2] = TempAdapterName; + + CTELogEvent( + IPDriverObject, + EVENT_TCPIP_INVALID_MASK, + 1, + 3, + stringList, + 0, + NULL + ); + + TCPTRACE(( + "IP: Invalid subnet Mask %ws specified for IP address %ws " + "on adapter %ws\n" + " This interface will not be initialized\n", + CurrentMask, + CurrentAddress, + TempAdapterName + )); + } else { + AddressList[GoodAddresses].ial_addr = AddressValue; + AddressList[GoodAddresses].ial_mask = MaskValue; + GoodAddresses++; + } + +nextone: + while(*CurrentAddress++ != UNICODE_NULL); + while(*CurrentMask++ != UNICODE_NULL); + + } + + ExFreePool(AddressString); + ExFreePool(MaskString); + ExFreePool(ValueString.Buffer); + + *NumAddr = GoodAddresses; + + if (GoodAddresses == 0) { + ExFreePool(AddressList); + AddressList = NULL; + } + + return AddressList; +} + +#endif // PNP_POWER + + +UINT +OpenIFConfig( + PNDIS_STRING ConfigName, + NDIS_HANDLE *Handle + ) + +/*++ + + Routine Description: + + Called when we want to open our per-info config info. We do so if we can, + otherwise we fail the request. + + Arguments: + ConfigName - Name of interface to open. + Handle - Where to return the handle. + + Return Value: + TRUE if we succeed, FALSE if we don't. + + +--*/ + +{ + NTSTATUS status; + HANDLE myRegKey; + UNICODE_STRING valueString; + WCHAR ServicesRegistryKey[] = + L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"; + UINT RetStatus = FALSE; + + + PAGED_CODE(); + + TempAdapterName = ConfigName->Buffer; + + // + // Get the size of the ConfigName string the easy way. + // + RtlInitUnicodeString(&valueString, (PWCHAR)ConfigName->Buffer); + + valueString.MaximumLength += sizeof(ServicesRegistryKey); + + valueString.Buffer = ExAllocatePool( + NonPagedPool, + valueString.MaximumLength + ); + + if (valueString.Buffer == NULL) { + CTELogEvent( + IPDriverObject, + EVENT_TCPIP_NO_ADAPTER_RESOURCES, + 4, + 1, + &ConfigName->Buffer, + 0, + NULL + ); + + TCPTRACE(("IP: Unable to allocate memory for reg key name\n")); + + return(FALSE); + } + + valueString.Length = 0; + valueString.Buffer[0] = UNICODE_NULL; + + // + // Build the key name for the tcpip parameters section and open key. + // + status = RtlAppendUnicodeToString(&valueString, ServicesRegistryKey); + + if (!NT_SUCCESS(status)) { + CTELogEvent( + IPDriverObject, + EVENT_TCPIP_ADAPTER_REG_FAILURE, + 1, + 1, + &ConfigName->Buffer, + 0, + NULL + ); + + TCPTRACE(("IP: Unable to append services name to key string\n")); + + goto done; + } + + status = RtlAppendUnicodeToString(&valueString, ConfigName->Buffer); + + if (!NT_SUCCESS(status)) { + CTELogEvent( + IPDriverObject, + EVENT_TCPIP_ADAPTER_REG_FAILURE, + 2, + 1, + &ConfigName->Buffer, + 0, + NULL + ); + + TCPTRACE(("IP: Unable to append adapter name to key string\n")); + + goto done; + } + + status = OpenRegKey(&myRegKey, valueString.Buffer); + + if (!NT_SUCCESS(status)) { + CTELogEvent( + IPDriverObject, + EVENT_TCPIP_ADAPTER_REG_FAILURE, + 4, + 1, + &ConfigName->Buffer, + 0, + NULL + ); + + TCPTRACE(( + "IP: Unable to open adapter registry key %ws\n", + valueString.Buffer + )); + + } else { + RetStatus = TRUE; + *Handle = myRegKey; + } + +done: + ExFreePool(valueString.Buffer); + + return RetStatus; +} + + +VOID +CloseIFConfig( + NDIS_HANDLE Handle + ) + +/*++ + + Routine Description: + + Close a per-interface config handle opened via OpenIFConfig(). + + Arguments: + Handle - Handle to be closed. + + Return Value: + + +--*/ + +{ + PAGED_CODE(); + + ZwClose(Handle); +} + + +IPConfigInfo * +IPGetConfig( + void + ) + +/*++ + +Routine Description: + + Provides IP configuration information for the NT environment. + +Arguments: + + None + +Return Value: + + A pointer to a structure containing the configuration information. + +--*/ + +{ + return(IPConfiguration); +} + + +void +IPFreeConfig( + IPConfigInfo *ConfigInfo + ) + +/*++ + +Routine Description: + + Frees the IP configuration structure allocated by IPGetConfig. + +Arguments: + + ConfigInfo - Pointer to the IP configuration information structure to free. + +Return Value: + + None. + +--*/ + +{ + int i; + +#ifndef _PNP_POWER + + NetConfigInfo *netConfiguration; + + + if (IPConfiguration != NULL) { + for (i = 0; i < IPConfiguration->ici_numnets; i++ ) { + netConfiguration = &(IPConfiguration->ici_netinfo[i]); + + if (netConfiguration->nci_driver.Buffer != NULL) { + CTEFreeString(&(netConfiguration->nci_driver)); + } + + if (netConfiguration->nci_configname.Buffer != NULL) { + CTEFreeString(&(netConfiguration->nci_configname)); + } + + if (netConfiguration->nci_reghandle != NULL) { + ZwClose(netConfiguration->nci_reghandle); + } + } + + CTEFreeMem(IPConfiguration->ici_netinfo); + CTEFreeMem(IPConfiguration); + } + +#else // _PNP_POWER + + if (IPConfiguration != NULL) { + CTEFreeMem(IPConfiguration); + } + +#endif // _PNP_POWER + + IPConfiguration = NULL; + + return; +} + +ulong +GetGMTDelta( + void + ) + +/*++ + +Routine Description: + + Returns the offset in milliseconds of the time zone of this machine + from GMT. + +Arguments: + + None. + +Return Value: + + Time in milliseconds between this time zone and GMT. + +--*/ + +{ + LARGE_INTEGER localTime, systemTime; + + // + // Get time zone bias in 100ns. + // + localTime.LowPart = 0; + localTime.HighPart = 0; + ExLocalTimeToSystemTime(&localTime, &systemTime); + + if ((localTime.LowPart != 0) || (localTime.HighPart != 0)) { + localTime = CTEConvert100nsToMilliseconds(systemTime); + } + + ASSERT(localTime.HighPart == 0); + + return(localTime.LowPart); +} + + +ulong +GetTime( + void + ) + +/*++ + +Routine Description: + + Returns the time in milliseconds since midnight. + +Arguments: + + None. + +Return Value: + + Time in milliseconds since midnight. + +--*/ + +{ + LARGE_INTEGER ntTime; + TIME_FIELDS breakdownTime; + ulong returnValue; + + KeQuerySystemTime(&ntTime); + RtlTimeToTimeFields(&ntTime, &breakdownTime); + + returnValue = breakdownTime.Hour * 60; + returnValue = (returnValue + breakdownTime.Minute) * 60; + returnValue = (returnValue + breakdownTime.Second) * 1000; + returnValue = returnValue + breakdownTime.Milliseconds; + + return(returnValue); +} + + +ulong +GetUnique32BitValue( + void + ) + +/*++ + +Routine Description: + + Returns a reasonably unique 32-bit number based on the system clock. + In NT, we take the current system time, convert it to milliseconds, + and return the low 32 bits. + +Arguments: + + None. + +Return Value: + + A reasonably unique 32-bit value. + +--*/ + +{ + LARGE_INTEGER ntTime, tmpTime; + + KeQuerySystemTime(&ntTime); + + tmpTime = CTEConvert100nsToMilliseconds(ntTime); + + return(tmpTime.LowPart); +} + + +uint +UseEtherSNAP( + PNDIS_STRING Name + ) + +/*++ + +Routine Description: + + Determines whether the EtherSNAP protocol should be used on an interface. + +Arguments: + + Name - The device name of the interface in question. + +Return Value: + + Nonzero if SNAP is to be used on the interface. Zero otherwise. + +--*/ + +{ + UNREFERENCED_PARAMETER(Name); + + // + // We currently set this on a global basis. + // + return(ArpUseEtherSnap); +} + + +void +GetAlwaysSourceRoute( + uint *pArpAlwaysSourceRoute, + uint *pIPAlwaysSourceRoute + ) + +/*++ + +Routine Description: + + Determines whether ARP should always turn on source routing in queries. + +Arguments: + + None. + +Return Value: + + Nonzero if source routing is always to be used. Zero otherwise. + +--*/ + +{ + // + // We currently set this on a global basis. + // + *pArpAlwaysSourceRoute = ArpAlwaysSourceRoute; + *pIPAlwaysSourceRoute = IPAlwaysSourceRoute; + return; +} + + +uint +GetArpCacheLife( + void + ) + +/*++ + +Routine Description: + + Get ArpCacheLife in seconds. + +Arguments: + + None. + +Return Value: + + Set to default if not found. + +--*/ + +{ + // + // We currently set this on a global basis. + // + return(ArpCacheLife); +} + + +#define IP_ADDRESS_STRING_LENGTH (16+2) // +2 for double NULL on MULTI_SZ + + +BOOLEAN +IPConvertStringToAddress( + IN PWCHAR AddressString, + OUT PULONG IpAddress + ) + +/*++ + +Routine Description + + This function converts an Internet standard 4-octet dotted decimal + IP address string into a numeric IP address. Unlike inet_addr(), this + routine does not support address strings of less than 4 octets nor does + it support octal and hexadecimal octets. + +Arguments + + AddressString - IP address in dotted decimal notation + IpAddress - Pointer to a variable to hold the resulting address + +Return Value: + + TRUE if the address string was converted. FALSE otherwise. + +--*/ + +{ + UNICODE_STRING unicodeString; + STRING aString; + UCHAR dataBuffer[IP_ADDRESS_STRING_LENGTH]; + NTSTATUS status; + PUCHAR addressPtr, cp, startPointer, endPointer; + ULONG digit, multiplier; + int i; + + + PAGED_CODE(); + + aString.Length = 0; + aString.MaximumLength = IP_ADDRESS_STRING_LENGTH; + aString.Buffer = dataBuffer; + + RtlInitUnicodeString(&unicodeString, AddressString); + + status = RtlUnicodeStringToAnsiString( + &aString, + &unicodeString, + FALSE + ); + + if (!NT_SUCCESS(status)) { + return(FALSE); + } + + *IpAddress = 0; + addressPtr = (PUCHAR) IpAddress; + startPointer = dataBuffer; + endPointer = dataBuffer; + i = 3; + + while (i >= 0) { + // + // Collect the characters up to a '.' or the end of the string. + // + while ((*endPointer != '.') && (*endPointer != '\0')) { + endPointer++; + } + + if (startPointer == endPointer) { + return(FALSE); + } + + // + // Convert the number. + // + + for ( cp = (endPointer - 1), multiplier = 1, digit = 0; + cp >= startPointer; + cp--, multiplier *= 10 + ) { + + if ((*cp < '0') || (*cp > '9') || (multiplier > 100)) { + return(FALSE); + } + + digit += (multiplier * ((ULONG) (*cp - '0'))); + } + + if (digit > 255) { + return(FALSE); + } + + addressPtr[i] = (UCHAR) digit; + + // + // We are finished if we have found and converted 4 octets and have + // no other characters left in the string. + // + if ( (i-- == 0) && + ((*endPointer == '\0') || (*endPointer == ' ')) + ) { + return(TRUE); + } + + if (*endPointer == '\0') { + return(FALSE); + } + + startPointer = ++endPointer; + } + + return(FALSE); +} + + +ULONG +RouteMatch( + IN WCHAR *RouteString, + IN IPAddr Address, + IN IPMask Mask, + OUT IPAddr *DestVal, + OUT IPMask *DestMask, + OUT IPAddr *GateVal, + OUT ULONG *Metric + ) + +/*++ + +Routine Description + + This function checks if a perisitent route should be assigned to + a given interface based on the interface address & mask. + +Arguments + + RouteString - A NULL-terminated route laid out as Dest,Mask,Gate. + Address - The IP address of the interface being processed. + Mask - The subnet mask of the interface being processed. + DestVal - A pointer to the decoded destination IP address. + DestVal - A pointer to the decoded destination subnet mask. + DestVal - A pointer to the decoded destination first hop gateway. + Metric - A pointer to the decoded route metric. + +Return Value: + + The route type, IRE_TYPE_DIRECT or IRE_TYPE_INDIRECT, if the route + should be added to the interface, IRE_TYPE_INVALID otherwise. + +--*/ + +{ +#define ROUTE_SEPARATOR L',' + + WCHAR *labelPtr; + WCHAR *indexPtr = RouteString; + ULONG i; + UNICODE_STRING ustring; + NTSTATUS status; + BOOLEAN noMetric = FALSE; + + + PAGED_CODE(); + + // + // The route is laid out in the string as "Dest,Mask,Gateway,Metric". + // The metric may not be there if this system was upgraded from + // NT 3.51. + // + // Parse the string and convert each label. + // + + for (i=0; i<4; i++) { + + labelPtr = indexPtr; + + while (1) { + + if (*indexPtr == UNICODE_NULL) { + if ((i < 2) || (indexPtr == labelPtr)) { + return(IRE_TYPE_INVALID); + } + + if (i == 2) { + // + // Old route - no metric. + // + noMetric = TRUE; + } + + break; + } + + if (*indexPtr == ROUTE_SEPARATOR) { + *indexPtr = UNICODE_NULL; + break; + } + + indexPtr++; + } + + switch(i) { + case 0: + if (!IPConvertStringToAddress(labelPtr, DestVal)) { + return(IRE_TYPE_INVALID); + } + break; + + case 1: + if (!IPConvertStringToAddress(labelPtr, DestMask)) { + return(IRE_TYPE_INVALID); + } + break; + + case 2: + if (!IPConvertStringToAddress(labelPtr, GateVal)) { + return(IRE_TYPE_INVALID); + } + break; + + case 3: + RtlInitUnicodeString(&ustring, labelPtr); + + status = RtlUnicodeStringToInteger( + &ustring, + 0, + Metric + ); + + if (!NT_SUCCESS(status)) { + return(IRE_TYPE_INVALID); + } + + break; + + default: + ASSERT(0); + return(IRE_TYPE_INVALID); + } + + if (noMetric) { + // + // Default to 1. + // + *Metric = 1; + break; + } + + indexPtr++; + } + + if (IP_ADDR_EQUAL(*GateVal, Address)) { + return(IRE_TYPE_DIRECT); + } + + if ( IP_ADDR_EQUAL((*GateVal & Mask), (Address & Mask)) ) { + return(IRE_TYPE_INDIRECT); + } + + return(IRE_TYPE_INVALID); +} + +ULONG +GetCurrentRouteTable( + IPRouteEntry **ppRouteTable + ) +/*++ + Routine Description + Allocates memory from non paged pool and fills it with the current route table + The caller must free the memory to non-paged pool + + Arguments + ppRouteTable Pointer to pointer to array of routes + + Return Value: + Count of routes in the table. If memory is allocated, *ppRouteTable will be non NULL + +--*/ +{ + ULONG ulTableCount,ulRouteCount; + uint uiValid,uiDataLeft; + IPRouteEntry routeEntry; + CTELockHandle Handle; + UCHAR ucContext[CONTEXT_SIZE]; + +#define ROUTE_TABLE_OVERFLOW 20 // This MUST NOT be zero + + ulTableCount = IPSInfo.ipsi_numroutes + ROUTE_TABLE_OVERFLOW; + + *ppRouteTable = ExAllocatePoolWithTag(NonPagedPool, + ulTableCount * sizeof(IPRouteEntry), + 'pI'); + ulRouteCount = 0; + + if(*ppRouteTable == NULL) + { + TCPTRACE(("IP: Couldnt allocate memory for route table\n")); + } + else + { + CTEGetLock(&RouteTableLock, &Handle); + + RtlZeroMemory((PVOID)ucContext,CONTEXT_SIZE); + + uiDataLeft = RTValidateContext((PVOID)ucContext, &uiValid); + + if(!uiValid) + { + CTEFreeLock(&RouteTableLock, Handle); + } + else + { + while(uiDataLeft) + { + if(ulRouteCount < ulTableCount) + { + uiDataLeft = RTReadNext((PVOID)ucContext, &routeEntry); + + (*ppRouteTable)[ulRouteCount++] = routeEntry; + } + else + { + TCPTRACE(("IP: Couldnt read out all routes. Increase ROUTE_TABLE_OVERFLOW\n")); + } + } + + CTEFreeLock(&RouteTableLock, Handle); + } + } + + return ulRouteCount; +} + + +VOID +SetPersistentRoutesForNTE( + IPAddr Address, + IPMask Mask, + ULONG IFIndex + ) + +/*++ + +Routine Description + + Adds persistent routes that match an interface. The routes are read + from a list in the registry. + +Arguments + + Address - The address of the new interface + Mask - The subnet mask of the new interface. + IFIndex - The index of the new interface. + +Return Value: + + None. + +--*/ + +{ +#define ROUTE_DATA_STRING_SIZE (51 * sizeof(WCHAR)) +#define BASIC_INFO_SIZE ( sizeof(KEY_VALUE_BASIC_INFORMATION) - \ + sizeof(WCHAR) + ROUTE_DATA_STRING_SIZE ) + IPAddr destVal; + IPMask destMask; + IPAddr gateVal; + ULONG metric; + ULONG enumIndex = 0; + UCHAR workbuf[BASIC_INFO_SIZE]; + PKEY_VALUE_BASIC_INFORMATION basicInfo = + (PKEY_VALUE_BASIC_INFORMATION) workbuf; + ULONG resultLength; + HANDLE regKey; + WCHAR IPRoutesRegistryKey[] = L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Tcpip\\Parameters\\PersistentRoutes"; + TDIObjectID id; + IPRouteEntry routeEntry,*pRouteTable; + ULONG ulRouteCount,i; + NTSTATUS status; + + PAGED_CODE(); + + pRouteTable = NULL; + + ulRouteCount = GetCurrentRouteTable(&pRouteTable); + + id.toi_entity.tei_entity = CL_NL_ENTITY; + id.toi_entity.tei_instance = 0; + id.toi_class = INFO_CLASS_PROTOCOL; + id.toi_type = INFO_TYPE_PROVIDER; + id.toi_id = IP_MIB_RTTABLE_ENTRY_ID; + + routeEntry.ire_index = IFIndex; + routeEntry.ire_metric2 = (ULONG) -1; + routeEntry.ire_metric3 = (ULONG) -1; + routeEntry.ire_metric4 = (ULONG) -1; + routeEntry.ire_proto = IRE_PROTO_LOCAL; + routeEntry.ire_age = 0; + routeEntry.ire_metric5 = (ULONG) -1; + + status = OpenRegKey(®Key, IPRoutesRegistryKey); + + if (NT_SUCCESS(status)) { + ULONG type; + + do { + status = ZwEnumerateValueKey( + regKey, + enumIndex, + KeyValueBasicInformation, + basicInfo, + BASIC_INFO_SIZE - sizeof(WCHAR), + &resultLength + ); + + if (!NT_SUCCESS(status)) { + if (status == STATUS_BUFFER_OVERFLOW) { + continue; + } + + break; + } + + if (basicInfo->Type != REG_SZ) { + continue; + } + + // + // Ensure NULL termination + // + basicInfo->Name[basicInfo->NameLength/sizeof(WCHAR)] = UNICODE_NULL; + basicInfo->NameLength += sizeof(WCHAR); + + type = RouteMatch( + basicInfo->Name, + Address, + Mask, + &destVal, + &destMask, + &gateVal, + &metric + ); + + if (type != IRE_TYPE_INVALID) + { + long setStatus; + ULONG ulFound; + + routeEntry.ire_dest = net_long(destVal), + routeEntry.ire_mask = net_long(destMask), + routeEntry.ire_nexthop = net_long(gateVal); + routeEntry.ire_type = type; + routeEntry.ire_metric1 = metric; + + ulFound = FALSE; + + for(i = 0; i < ulRouteCount; i++) + { + if((routeEntry.ire_dest == pRouteTable[i].ire_dest) && + (routeEntry.ire_mask == pRouteTable[i].ire_mask)) + { + ulFound = TRUE; + + break; + } + } + + if(!ulFound) + { + + setStatus = IPSetInfo( + &id, + &routeEntry, + sizeof(IPRouteEntry) + ); +#if DBG + if (setStatus != IP_SUCCESS) + { + TCPTRACE(( + "IP: set of sticky route [%x, %x, %x] failed, status %d\n", + destVal, + destMask, + gateVal, + metric, + setStatus + )); + } +#endif // DBG + } + + } + + } while (++enumIndex); + + ZwClose(regKey); + } + + if(pRouteTable) + { + ExFreePool(pRouteTable); + } +} + |