diff options
Diffstat (limited to '')
-rw-r--r-- | private/ntos/tdi/tcpip/tcp/ntinit.c | 1038 |
1 files changed, 1038 insertions, 0 deletions
diff --git a/private/ntos/tdi/tcpip/tcp/ntinit.c b/private/ntos/tdi/tcpip/tcp/ntinit.c new file mode 100644 index 000000000..e1fdbd7f7 --- /dev/null +++ b/private/ntos/tdi/tcpip/tcp/ntinit.c @@ -0,0 +1,1038 @@ +/*++ + +Copyright (c) 1991 Microsoft Corporation + +Module Name: + + ntinit.c + +Abstract: + + NT specific routines for loading and configuring the TCP/UDP driver. + +Author: + + Mike Massa (mikemas) Aug 13, 1993 + +Revision History: + + Who When What + -------- -------- ---------------------------------------------- + mikemas 08-13-93 created + +Notes: + +--*/ + +#include <oscfg.h> +#include <ntddip.h> +#include <ndis.h> +#include <cxport.h> +#include <tdi.h> +#include <tdikrnl.h> +#include <tdint.h> +#include <tdistat.h> +#include <tdiinfo.h> +#include <ip.h> + +#include "queue.h" +#include "addr.h" +#include "tcp.h" +#include "tcb.h" +#include "udp.h" +#include "raw.h" +#include "tcpconn.h" +#include "tcpcfg.h" +#include <ntddtcp.h> +#include "secfltr.h" + +// +// Global variables. +// +PDRIVER_OBJECT TCPDriverObject = NULL; +PDEVICE_OBJECT TCPDeviceObject = NULL; +PDEVICE_OBJECT UDPDeviceObject = NULL; +PDEVICE_OBJECT RawIPDeviceObject = NULL; +extern PDEVICE_OBJECT IPDeviceObject; + +// +//Place holder for Maximum duplicate acks we would like +//to see before we do fast retransmit +// +#if FAST_RETRANSMIT +uint MaxDupAcks; +#endif + + +#ifdef _PNP_POWER + +HANDLE TCPRegistrationHandle; +HANDLE UDPRegistrationHandle; +HANDLE IPRegistrationHandle; + +#endif + +#ifdef SYN_ATTACK +BOOLEAN SynAttackProtect; //if TRUE, syn-att protection checks + // are made +uint TCPPortsExhausted; //# of ports exhausted +uint TCPMaxPortsExhausted; //Max # of ports that must be exhausted + // for syn-att protection to kick in +uint TCPMaxPortsExhaustedLW; //Low-watermark of # of ports exhausted + //When reached, we revert to normal + // count for syn-ack retries +uint TCPMaxHalfOpen; //Max # of half-open connections allowed + // before we dec. the syn-ack retries +uint TCPMaxHalfOpenRetried; //Max # of half-open conn. that have + // been retried at least 1 time +uint TCPMaxHalfOpenRetriedLW; //Low-watermark of the above. When + // go down to it, we revert to normal + // # of retries for syn-acks +uint TCPHalfOpen; //# of half-open connections +uint TCPHalfOpenRetried; //# of half-open conn. that have been + //retried at least once +#endif +// +// External function prototypes +// + +int +tlinit( + void + ); + +NTSTATUS +TCPDispatch( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ); + +NTSTATUS +TCPDispatchInternalDeviceControl( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ); + +NTSTATUS +IPDispatch( + IN PDEVICE_OBJECT DeviceObject, + IN PIRP Irp + ); + +NTSTATUS +IPDriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ); + +NTSTATUS +GetRegMultiSZValue( + HANDLE KeyHandle, + PWCHAR ValueName, + PUNICODE_STRING ValueData + ); + +PWCHAR +EnumRegMultiSz( + IN PWCHAR MszString, + IN ULONG MszStringLength, + IN ULONG StringIndex + ); + +// +// Local funcion prototypes +// +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ); + +void * +TLRegisterProtocol( + uchar Protocol, + void *RcvHandler, + void *XmitHandler, + void *StatusHandler, + void *RcvCmpltHandler + ); + +IP_STATUS +TLGetIPInfo( + IPInfo *Buffer, + int Size + ); + +uchar +TCPGetConfigInfo( + void + ); + +NTSTATUS +TCPInitializeParameter( + HANDLE KeyHandle, + PWCHAR ValueName, + PULONG Value + ); + +#ifdef SECFLTR + +uint +EnumSecurityFilterValue( + PNDIS_STRING FilterList, + ulong Index, + ulong *FilterValue + ); + +#endif // SECFLTR + +#ifdef RASAUTODIAL +VOID +TCPAcdBind(); +#endif // RASAUTODIAL + + +#ifdef ALLOC_PRAGMA + +#pragma alloc_text(INIT, DriverEntry) +#pragma alloc_text(INIT, TLRegisterProtocol) +#pragma alloc_text(INIT, TLGetIPInfo) +#pragma alloc_text(INIT, TCPGetConfigInfo) +#pragma alloc_text(INIT, TCPInitializeParameter) + +#ifdef SECFLTR +#pragma alloc_text(PAGE, EnumSecurityFilterValue) +#endif // SECFLTR + +#ifdef RASAUTODIAL +#pragma alloc_text(INIT, TCPAcdBind) +#endif // RASAUTODIAL + +#endif // ALLOC_PRAGMA + + +// +// Function definitions +// +NTSTATUS +DriverEntry( + IN PDRIVER_OBJECT DriverObject, + IN PUNICODE_STRING RegistryPath + ) + +/*++ + +Routine Description: + + Initialization routine for the TCP/UDP driver. + +Arguments: + + DriverObject - Pointer to the TCP driver object created by the system. + DeviceDescription - The name of TCP's node in the registry. + +Return Value: + + The final status from the initialization operation. + +--*/ + +{ + NTSTATUS status; + UNICODE_STRING deviceName; + USHORT i; + int initStatus; + + +#ifdef _PNP_POWER + TdiInitialize(); +#endif + +#ifdef SECFLTR + // + // IP calls the security filter code, so initialize it first. + // + InitializeSecurityFilters(); + +#endif // SECFLTR + + // + // Initialize IP + // + status = IPDriverEntry(DriverObject, RegistryPath); + + if (!NT_SUCCESS(status)) { + TCPTRACE(("Tcpip: IP initialization failed, status %lx\n", status)); + return(status); + } + + // + // Initialize TCP, UDP, and RawIP + // + TCPDriverObject = DriverObject; + + // + // Create the device objects. IoCreateDevice zeroes the memory + // occupied by the object. + // + + RtlInitUnicodeString(&deviceName, DD_TCP_DEVICE_NAME); + + status = IoCreateDevice( + DriverObject, + 0, + &deviceName, + FILE_DEVICE_NETWORK, + 0, + FALSE, + &TCPDeviceObject + ); + + if (!NT_SUCCESS(status)) { + CTELogEvent( + DriverObject, + EVENT_TCPIP_CREATE_DEVICE_FAILED, + 1, + 1, + &deviceName.Buffer, + 0, + NULL + ); + + TCPTRACE(( + "TCP: Failed to create TCP device object, status %lx\n", + status + )); + goto init_failed; + } + + RtlInitUnicodeString(&deviceName, DD_UDP_DEVICE_NAME); + + status = IoCreateDevice( + DriverObject, + 0, + &deviceName, + FILE_DEVICE_NETWORK, + 0, + FALSE, + &UDPDeviceObject + ); + + if (!NT_SUCCESS(status)) { + CTELogEvent( + DriverObject, + EVENT_TCPIP_CREATE_DEVICE_FAILED, + 1, + 1, + &deviceName.Buffer, + 0, + NULL + ); + + TCPTRACE(( + "TCP: Failed to create UDP device object, status %lx\n", + status + )); + goto init_failed; + } + + RtlInitUnicodeString(&deviceName, DD_RAW_IP_DEVICE_NAME); + + status = IoCreateDevice( + DriverObject, + 0, + &deviceName, + FILE_DEVICE_NETWORK, + 0, + FALSE, + &RawIPDeviceObject + ); + + if (!NT_SUCCESS(status)) { + CTELogEvent( + DriverObject, + EVENT_TCPIP_CREATE_DEVICE_FAILED, + 1, + 1, + &deviceName.Buffer, + 0, + NULL + ); + + TCPTRACE(( + "TCP: Failed to create Raw IP device object, status %lx\n", + status + )); + goto init_failed; + } + + // + // Initialize the driver object + // + DriverObject->DriverUnload = NULL; + DriverObject->FastIoDispatch = NULL; + for (i=0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) { + DriverObject->MajorFunction[i] = TCPDispatch; + } + + // + // We special case Internal Device Controls because they are the + // hot path for kernel-mode clients. + // + DriverObject->MajorFunction[IRP_MJ_INTERNAL_DEVICE_CONTROL] = + TCPDispatchInternalDeviceControl; + + // + // Intialize the device objects. + // + TCPDeviceObject->Flags |= DO_DIRECT_IO; + UDPDeviceObject->Flags |= DO_DIRECT_IO; + RawIPDeviceObject->Flags |= DO_DIRECT_IO; + + // + // Finally, initialize the stack. + // + initStatus = tlinit(); + + if (initStatus == TRUE) { +#ifdef RASAUTODIAL + // + // Get the automatic connection driver + // entry points. + // + TCPAcdBind(); +#endif // RASAUTODIAL + + +#ifdef _PNP_POWER + + RtlInitUnicodeString(&deviceName, DD_TCP_DEVICE_NAME); + (void)TdiRegisterDeviceObject(&deviceName,&TCPRegistrationHandle); + + RtlInitUnicodeString(&deviceName, DD_UDP_DEVICE_NAME); + (void)TdiRegisterDeviceObject(&deviceName,&UDPRegistrationHandle); + + RtlInitUnicodeString(&deviceName, DD_RAW_IP_DEVICE_NAME); + (void)TdiRegisterDeviceObject(&deviceName,&IPRegistrationHandle); + +#endif + return(STATUS_SUCCESS); + } + + TCPTRACE(( + "Tcpip: TCP/UDP initialization failed, but IP will be available.\n" + )); + + CTELogEvent( + DriverObject, + EVENT_TCPIP_TCP_INIT_FAILED, + 1, + 0, + NULL, + 0, + NULL + ); + status = STATUS_UNSUCCESSFUL; + + +init_failed: + + // + // IP has successfully started, but TCP & UDP failed. Set the + // Dispatch routine to point to IP only, since the TCP and UDP + // devices don't exist. + // + + if (TCPDeviceObject != NULL) { + IoDeleteDevice(TCPDeviceObject); + } + + if (UDPDeviceObject != NULL) { + IoDeleteDevice(UDPDeviceObject); + } + + if (RawIPDeviceObject != NULL) { + IoDeleteDevice(RawIPDeviceObject); + } + + for (i=0; i <= IRP_MJ_MAXIMUM_FUNCTION; i++) { + DriverObject->MajorFunction[i] = IPDispatch; + } + + return(STATUS_SUCCESS); +} + + +IP_STATUS +TLGetIPInfo( + IPInfo *Buffer, + int Size + ) + +/*++ + +Routine Description: + + Returns information necessary for TCP to call into IP. + +Arguments: + + Buffer - A pointer to the IP information structure. + + Size - The size of Buffer. + +Return Value: + + The IP status of the operation. + +--*/ + +{ + return(IPGetInfo(Buffer, Size)); +} + + +void * +TLRegisterProtocol( + uchar Protocol, + void *RcvHandler, + void *XmitHandler, + void *StatusHandler, + void *RcvCmpltHandler + ) + +/*++ + +Routine Description: + + Calls the IP driver's protocol registration function. + +Arguments: + + Protocol - The protocol number to register. + + RcvHandler - Transport's packet receive handler. + + XmitHandler - Transport's packet transmit complete handler. + + StatusHandler - Transport's status update handler. + + RcvCmpltHandler - Transport's receive complete handler + +Return Value: + + A context value for the protocol to pass to IP when transmitting. + +--*/ + +{ + return(IPRegisterProtocol( + Protocol, + RcvHandler, + XmitHandler, + StatusHandler, + RcvCmpltHandler + ) + ); +} + + +// +// Interval in milliseconds between keepalive transmissions until a +// response is received. +// +#define DEFAULT_KEEPALIVE_INTERVAL 1000 + +// +// time to first keepalive transmission. 2 hours == 7,200,000 milliseconds +// +#define DEFAULT_KEEPALIVE_TIME 7200000 + +#ifdef SYN_ATTACK +#define MIN_THRESHOLD_MAX_HO 100 +#define MIN_THRESHOLD_MAX_HO_RETRIED 80 +#endif + +uchar +TCPGetConfigInfo( + void + ) + +/*++ + +Routine Description: + + Initializes TCP global configuration parameters. + +Arguments: + + None. + +Return Value: + + Zero on failure, nonzero on success. + +--*/ + +{ + HANDLE keyHandle; + NTSTATUS status; + OBJECT_ATTRIBUTES objectAttributes; + UNICODE_STRING UKeyName; + ULONG maxConnectRexmits = 0; + ULONG maxConnectResponseRexmits = 0; + ULONG maxDataRexmits = 0; + ULONG pptpmaxDataRexmits = 0; + ULONG useRFC1122UrgentPointer = 0; + BOOLEAN AsSystem; + + + // + // Initialize to the defaults in case an error occurs somewhere. + // + KAInterval = DEFAULT_KEEPALIVE_INTERVAL; + KeepAliveTime = DEFAULT_KEEPALIVE_TIME; + PMTUDiscovery = TRUE; + PMTUBHDetect = FALSE; + DeadGWDetect = TRUE; + DefaultRcvWin = 0; // Automagically pick a reasonable one. + MaxConnections = DEFAULT_MAX_CONNECTIONS; + maxConnectRexmits = MAX_CONNECT_REXMIT_CNT; + maxConnectResponseRexmits = MAX_CONNECT_RESPONSE_REXMIT_CNT; + pptpmaxDataRexmits = maxDataRexmits = MAX_REXMIT_CNT; + BSDUrgent = TRUE; + FinWait2TO = FIN_WAIT2_TO; + NTWMaxConnectCount = NTW_MAX_CONNECT_COUNT; + NTWMaxConnectTime = NTW_MAX_CONNECT_TIME; + MaxUserPort = MAX_USER_PORT; + + +#if FAST_RETRANSMIT +// Default number of duplicate acks + MaxDupAcks = 2; +#endif + + +#ifdef SYN_ATTACK + SynAttackProtect = FALSE; //by default it is always off + if (MmIsThisAnNtAsSystem()) { + TCPMaxPortsExhausted = 5; + TCPMaxHalfOpen = 100; + TCPMaxHalfOpenRetried = 80; + } + else { + TCPMaxPortsExhausted = 5; + TCPMaxHalfOpen = 500; + TCPMaxHalfOpenRetried = 400; + } +#endif + +#ifdef SECFLTR + SecurityFilteringEnabled = FALSE; +#endif // SECFLTR + + + // + // Read the TCP optional (hidden) registry parameters. + // + RtlInitUnicodeString( + &UKeyName, + L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Tcpip\\Parameters" + ); + + memset(&objectAttributes, 0, sizeof(OBJECT_ATTRIBUTES)); + + InitializeObjectAttributes( + &objectAttributes, + &UKeyName, + OBJ_CASE_INSENSITIVE, + NULL, + NULL + ); + + status = ZwOpenKey( + &keyHandle, + KEY_READ, + &objectAttributes + ); + + if (NT_SUCCESS(status)) { + + TCPInitializeParameter( + keyHandle, + L"KeepAliveInterval", + &KAInterval + ); + + TCPInitializeParameter( + keyHandle, + L"KeepAliveTime", + &KeepAliveTime + ); + + TCPInitializeParameter( + keyHandle, + L"EnablePMTUBHDetect", + &PMTUBHDetect + ); + + TCPInitializeParameter( + keyHandle, + L"TcpWindowSize", + &DefaultRcvWin + ); + + TCPInitializeParameter( + keyHandle, + L"TcpNumConnections", + &MaxConnections + ); + + TCPInitializeParameter( + keyHandle, + L"TcpMaxConnectRetransmissions", + &maxConnectRexmits + ); + + if (maxConnectRexmits > 255) { + maxConnectRexmits = 255; + } + + TCPInitializeParameter( + keyHandle, + L"TcpMaxConnectResponseRetransmissions", + &maxConnectResponseRexmits + ); + + if (maxConnectResponseRexmits > 255) { + maxConnectResponseRexmits = 255; + } + + TCPInitializeParameter( + keyHandle, + L"TcpMaxDataRetransmissions", + &maxDataRexmits + ); + + if (maxDataRexmits > 255) { + maxDataRexmits = 255; + } + + +#if FAST_RETRANSMIT + // Limit the MaxDupAcks to 3 + + TCPInitializeParameter( + keyHandle, + L"TcpMaxDupAcks", + &MaxDupAcks + ); + + if (MaxDupAcks > 3) { + MaxDupAcks = 3; + } + if (MaxDupAcks < 0) { + MaxDupAcks = 1; + } +#endif + + + +#ifdef SYN_ATTACK + + TCPInitializeParameter( + keyHandle, + L"SynAttackProtect", + (unsigned long *)&SynAttackProtect + ); + + + if (SynAttackProtect) { + + // + // We don't want syn-attack protection to kick in if the user + // has set the MaxConnectResponseRetransmissions to lower than + // a certain threshold. + // + if (maxConnectResponseRexmits >= MAX_CONNECT_RESPONSE_REXMIT_CNT){ + + TCPInitializeParameter( + keyHandle, + L"TCPMaxPortsExhausted", + &TCPMaxPortsExhausted + ); + + TCPMaxPortsExhaustedLW = MAX((TCPMaxPortsExhausted >> 1) + (TCPMaxPortsExhausted >> 2), 1); + + TCPInitializeParameter( + keyHandle, + L"TCPMaxHalfOpen", + &TCPMaxHalfOpen + ); + + if (TCPMaxHalfOpen < MIN_THRESHOLD_MAX_HO) { + TCPMaxHalfOpen = MIN_THRESHOLD_MAX_HO; + } + + TCPInitializeParameter( + keyHandle, + L"TCPMaxHalfOpenRetried", + &TCPMaxHalfOpenRetried + ); + + if ( + (TCPMaxHalfOpenRetried > TCPMaxHalfOpen) || + (TCPMaxHalfOpenRetried < MIN_THRESHOLD_MAX_HO_RETRIED) + ) + + { + TCPMaxHalfOpenRetried = MIN_THRESHOLD_MAX_HO_RETRIED; + } + + TCPMaxHalfOpenRetriedLW = (TCPMaxHalfOpenRetried >> 1) + + (TCPMaxHalfOpenRetried >> 2); + } + else { + SynAttackProtect = FALSE; + } + + } +#endif + + // + // If we fail, then set to same value as maxDataRexmit so that the + // max(pptpmaxDataRexmit,maxDataRexmit) is a decent value + // Need this since TCPInitializeParameter no longer "initializes" + // to a default value + // + + if(TCPInitializeParameter(keyHandle, + L"PPTPTcpMaxDataRetransmissions", + &pptpmaxDataRexmits) != STATUS_SUCCESS) + { + pptpmaxDataRexmits = maxDataRexmits; + } + + if (pptpmaxDataRexmits > 255) { + pptpmaxDataRexmits = 255; + } + + TCPInitializeParameter( + keyHandle, + L"TcpUseRFC1122UrgentPointer", + &useRFC1122UrgentPointer + ); + + if (useRFC1122UrgentPointer) { + BSDUrgent = FALSE; + } + + TCPInitializeParameter( + keyHandle, + L"TcpTimedWaitDelay", + &FinWait2TO + ); + + if (FinWait2TO < 30) { + FinWait2TO = 30; + } + if (FinWait2TO > 300) { + FinWait2TO = 300; + } + FinWait2TO = MS_TO_TICKS(FinWait2TO*1000); + + NTWMaxConnectTime = MS_TO_TICKS(NTWMaxConnectTime*1000); + + TCPInitializeParameter( + keyHandle, + L"MaxUserPort", + &MaxUserPort + ); + + if (MaxUserPort < 5000) { + MaxUserPort = 5000; + } + if (MaxUserPort > 65534) { + MaxUserPort = 65534; + } + + // + // Read a few IP optional (hidden) registry parameters that TCP + // cares about. + // + TCPInitializeParameter( + keyHandle, + L"EnablePMTUDiscovery", + &PMTUDiscovery + ); + + TCPInitializeParameter( + keyHandle, + L"EnableDeadGWDetect", + &DeadGWDetect + ); + +#ifdef SECFLTR + TCPInitializeParameter( + keyHandle, + L"EnableSecurityFilters", + &SecurityFilteringEnabled + ); +#endif // SECFLTR + + ZwClose(keyHandle); + } + + MaxConnectRexmitCount = maxConnectRexmits; + MaxConnectResponseRexmitCount = maxConnectResponseRexmits; +#ifdef SYN_ATTACK + MaxConnectResponseRexmitCountTmp = MaxConnectResponseRexmitCount; +#endif + + // + // Use the greater of the two, hence both values should be valid + // + + MaxDataRexmitCount = (maxDataRexmits > pptpmaxDataRexmits ? maxDataRexmits : pptpmaxDataRexmits) ; + + return(1); +} + + +#define WORK_BUFFER_SIZE 256 + +NTSTATUS +TCPInitializeParameter( + HANDLE KeyHandle, + PWCHAR ValueName, + PULONG Value + ) + +/*++ + +Routine Description: + + Initializes a ULONG parameter from the registry or to a default + parameter if accessing the registry value fails. + +Arguments: + + KeyHandle - An open handle to the registry key for the parameter. + ValueName - The UNICODE name of the registry value to read. + Value - The ULONG into which to put the data. + DefaultValue - The default to assign if reading the registry fails. + +Return Value: + + None. + +--*/ + +{ + NTSTATUS status; + ULONG resultLength; + PKEY_VALUE_FULL_INFORMATION keyValueFullInformation; + UCHAR keybuf[WORK_BUFFER_SIZE]; + UNICODE_STRING UValueName; + + + RtlInitUnicodeString(&UValueName, ValueName); + + keyValueFullInformation = (PKEY_VALUE_FULL_INFORMATION)keybuf; + RtlZeroMemory(keyValueFullInformation, sizeof(keyValueFullInformation)); + + status = ZwQueryValueKey( + KeyHandle, + &UValueName, + KeyValueFullInformation, + keyValueFullInformation, + WORK_BUFFER_SIZE, + &resultLength + ); + + if (status == STATUS_SUCCESS) { + if (keyValueFullInformation->Type == REG_DWORD) { + *Value = *((ULONG UNALIGNED *) ((PCHAR)keyValueFullInformation + + keyValueFullInformation->DataOffset)); + } + } + + return(status); +} + + +#ifdef SECFLTR + +TDI_STATUS +GetSecurityFilterList( + NDIS_HANDLE ConfigHandle, + ulong Protocol, + PNDIS_STRING FilterList + ) +{ + PWCHAR parameterName; + TDI_STATUS status; + + + if (Protocol == PROTOCOL_TCP) { + parameterName = L"TcpAllowedPorts"; + } + else if (Protocol == PROTOCOL_UDP) { + parameterName = L"UdpAllowedPorts"; + } + else { + parameterName = L"RawIpAllowedProtocols"; + } + + status = GetRegMultiSZValue( + ConfigHandle, + parameterName, + FilterList + ); + + if (!NT_SUCCESS(status)) { + FilterList->Length = 0; + } + + return(status); +} + + +uint +EnumSecurityFilterValue( + PNDIS_STRING FilterList, + ulong Index, + ulong *FilterValue + ) +{ + PWCHAR valueString; + UNICODE_STRING unicodeString; + NTSTATUS status; + + + PAGED_CODE(); + + + valueString = EnumRegMultiSz( + FilterList->Buffer, + FilterList->Length, + Index + ); + + if ((valueString == NULL) || (valueString[0] == UNICODE_NULL)) { + return(FALSE); + } + + RtlInitUnicodeString(&unicodeString, valueString); + + status = RtlUnicodeStringToInteger(&unicodeString, 0, FilterValue); + + if (!(NT_SUCCESS(status))) { + TCPTRACE(("TCP: Invalid filter value %ws\n", valueString)); + return(FALSE); + } + + return(TRUE); +} + +#endif // SECFLTR |