Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

3361 lines
74 KiB

/*++
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(&regKey, 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);
}
}