windows-nt/Source/XPSP1/NT/termsrv/drivers/td/tdtcp/tdtcp.c

1285 lines
35 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/****************************************************************************/
// tdtcp.c
//
// TDI based TCP transport specific routines.
//
// Copyright (C) 1997-2000 Microsoft Corporation
/****************************************************************************/
#include <ntddk.h>
#include <tdi.h>
#include <ntddtcp.h>
#include <tdiinfo.h>
#include <tdistat.h>
#include <ipinfo.h>
#include <winstaw.h>
#define _DEFCHARINFO_
#include <icadd.h>
#include <ctxdd.h>
#include <sdapi.h>
#include <td.h>
#include "tdtdi.h"
#include "tdtcp.h"
#ifdef _HYDRA_
// This becomes the device name
PWCHAR ModuleName = L"tdtcp";
#endif
#define REGISTRY_SERVICES \
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\"
#define REGISTRY_TCP_LINKAGE \
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Tcpip\\Linkage"
#define REGISTRY_TCP_INTERFACES \
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces\\"
// \nt\private\inc\tcpinfo.h
#define TCP_SOCKET_NODELAY 1
#define TL_INSTANCE 0
#if DBG
ULONG
DbgPrint(
PCH Format,
...
);
#define DBGPRINT(x) DbgPrint x
#if DBGTRACE
#define TRACE0(x) DbgPrint x
#define TRACE1(x) DbgPrint x
#else
#define TRACE0(x)
#define TRACE1(x)
#endif
#else
#define DBGPRINT(x)
#define TRACE0(x)
#define TRACE1(x)
#endif
/*=============================================================================
== External Functions Defined
=============================================================================*/
// These are called by TDICOM
NTSTATUS TdiDeviceOpen( PTD, PSD_OPEN );
NTSTATUS TdiDeviceClose( PTD, PSD_CLOSE );
NTSTATUS TdiDeviceOpenEndpoint( PTD, PVOID, ULONG );
NTSTATUS TdiDeviceBuildTransportNameAndAddress( PTD, PICA_STACK_ADDRESS,
PUNICODE_STRING,
PTRANSPORT_ADDRESS *, PULONG );
NTSTATUS TdiDeviceBuildWildcardAddress( PTD, PTRANSPORT_ADDRESS *, PULONG );
NTSTATUS TdiDeviceWaitForDatagramConnection( PTD, PFILE_OBJECT, PDEVICE_OBJECT,
PTRANSPORT_ADDRESS *, PULONG );
NTSTATUS TdiDeviceCompleteDatagramConnection( PTD, PFILE_OBJECT, PDEVICE_OBJECT, PTRANSPORT_ADDRESS, ULONG );
NTSTATUS TdiDeviceConnectionSend( PTD );
NTSTATUS TdiDeviceReadComplete( PTD, PUCHAR, PULONG );
/*=============================================================================
== External Functions Referenced
=============================================================================*/
NTSTATUS MemoryAllocate( ULONG, PVOID * );
VOID MemoryFree( PVOID );
/*=============================================================================
== Internal Functions Defined
=============================================================================*/
NTSTATUS _TcpGetTransportAddress( PTD, int, PULONG );
VOID
_UnicodeToAnsi(
CHAR * pAnsiString,
ULONG lAnsiMax,
WCHAR * pUnicodeString
);
unsigned long
_inet_addr(
IN const char *cp
);
NTSTATUS
_TcpSetNagle(
IN PFILE_OBJECT pFileObject,
IN PDEVICE_OBJECT DeviceObject,
IN BOOLEAN Flag
);
NTSTATUS
_TdiTcpSetInformation (
IN PFILE_OBJECT FileObject,
IN PDEVICE_OBJECT DeviceObject,
IN ULONG Entity,
IN ULONG Class,
IN ULONG Type,
IN ULONG Id,
IN PVOID Value,
IN ULONG ValueLength,
IN BOOLEAN WaitForCompletion
);
NTSTATUS
_OpenRegKey(
PHANDLE HandlePtr,
PWCHAR KeyName
);
NTSTATUS
_GetRegDWORDValue(
HANDLE KeyHandle,
PWCHAR ValueName,
PULONG ValueData
);
NTSTATUS
_GetRegStringValue(
HANDLE KeyHandle,
PWCHAR ValueName,
PKEY_VALUE_PARTIAL_INFORMATION *ValueData,
PUSHORT ValueSize
);
NTSTATUS
_GetRegMultiSZValue(
HANDLE KeyHandle,
PWCHAR ValueName,
PUNICODE_STRING ValueData
);
NTSTATUS
_GetRegSZValue(
HANDLE KeyHandle,
PWCHAR ValueName,
PUNICODE_STRING ValueData,
PULONG ValueType
);
PWCHAR
_EnumRegMultiSz(
PWCHAR MszString,
ULONG MszStringLength,
ULONG StringIndex
);
VOID
GetGUID(
OUT PUNICODE_STRING szGuid ,
IN int Lana
);
/*=============================================================================
== Global variables
=============================================================================*/
USHORT TdiDeviceEndpointType = TdiConnectionStream; // tdicom\tdtdi.h
USHORT TdiDeviceAddressType = TDI_ADDRESS_TYPE_IP; // TDI address type
USHORT TdiDeviceInBufHeader = 0; // For packet oriented protocols
/*******************************************************************************
*
* TdiDeviceOpen
*
* Allocate and initialize private data structures
*
* ENTRY:
* pTd (input)
* Pointer to TD data structure
* pSdOpen (input/output)
* Points to the parameter structure SD_OPEN.
*
* EXIT:
* STATUS_SUCCESS - no error
*
******************************************************************************/
NTSTATUS
TdiDeviceOpen( PTD pTd, PSD_OPEN pSdOpen )
{
return( STATUS_SUCCESS );
}
/*******************************************************************************
*
* TdiDeviceClose
*
* Close transport driver
*
* NOTE: this must not close the current connection endpoint
*
* ENTRY:
* pTd (input)
* Pointer to TD data structure
* pSdClose (input/output)
* Points to the parameter structure SD_CLOSE.
*
* EXIT:
* STATUS_SUCCESS - no error
*
******************************************************************************/
NTSTATUS
TdiDeviceClose( PTD pTd, PSD_CLOSE pSdClose )
{
return( STATUS_SUCCESS );
}
/*******************************************************************************
*
* TdiDeviceOpenEndpoint
*
* Open an existing endpoint
*
* ENTRY:
* pTd (input)
* Pointer to TD data structure
* pIcaEndpoint (input)
* Pointer to ICA endpoint structure
* IcaEndpointLength (input)
* length of endpoint data
*
* EXIT:
* STATUS_SUCCESS - no error
*
******************************************************************************/
NTSTATUS
TdiDeviceOpenEndpoint(
PTD pTd,
PVOID pIcaEndpoint,
ULONG IcaEndpointLength
)
{
PTDTDI pTdTdi;
NTSTATUS Status;
BOOLEAN Flag;
pTdTdi = (PTDTDI) pTd->pAfd;
/*
* JohnR: Adaptive TCP flow control. 03/02/97
*
* If the OutBufDelay is 0, there is no OutBuf timer,
* and no Nagles. This setting is for the most response time
* sensitive networks with the side effect of sending smaller
* segments.
*
* If the OutBufDelay is greater than 1, the standard CITRIX
* ICA timer is used to determine at the WD level when to
* send a segment. No nagling is enabled since the extra
* delay would not be benefitial.
*
* The new OutBufDelay == 1, means that the WD will treat the
* OutBufDelay as if it were 0, but the TCP code will enable
* the "Nagle" algorithum. This algorithum will send data
* immediately if no un-acknowledged segments are outstanding,
* OR if half of the send window is filled. If not, data is
* stored locally until either a segment acknowledge comes in,
* or more data is sent causing half the send window to fill.
* This has the advantage of dynamically sizing our "outbuf timer"
* to be the round trip time of the network, and not some
* arbritrary fixed value.
*/
if( pTdTdi->OutBufDelay == 1 ) {
/*
* OutBufDelay == 1 means NAGLE only.
*/
Flag = TRUE;
}
else {
/*
* Turn off nagling for any OutBufDelay timer value, or 0
*/
Flag = FALSE;
}
Status = _TcpSetNagle(
pTd->pFileObject,
pTd->pDeviceObject,
Flag
);
DBGPRINT(("TdiDeviceOpenEndpoint: SetNagle 0x%x Result 0x%x\n",Flag,Status));
return( STATUS_SUCCESS );
}
/*****************************************************************************
*
* TdiDeviceBuildTransportNameAndAddress
*
* Build the Transport Name and Address given an optional ICA_STACK_ADDRESS,
* or the Lana value from the pTd->Params structure.
*
* ENTRY:
*
* pTd (input)
* pointer to TD data structure
* pLocalAddress (input)
* pointer to local address to use (OPTIONAL)
* pTransportName (output)
* pointer to UNICODE_STRING to return transport name
* NOTE: the buffer pointed to be pTransportName.Buffer must
* be free'd by the caller
* ppTransportAddress (output)
* pointer to location to return TRANSPORT_ADDRESS structure
* NOTE: the transport address buffer must be free'd by the caller
* pTransportAddressLength (output)
* pointer to location to return TransportAddress length
*
* EXIT:
* STATUS_SUCCESS - Success
*
****************************************************************************/
NTSTATUS
TdiDeviceBuildTransportNameAndAddress(
PTD pTd,
PICA_STACK_ADDRESS pLocalAddress,
PUNICODE_STRING pTransportName,
PTRANSPORT_ADDRESS *ppTransportAddress,
PULONG pTransportAddressLength
)
{
PTDI_ADDRESS_IP pIpAddress;
int Lana;
NTSTATUS Status;
/*
* For TCP, the transport device name is fixed,
* so just allocate and initialize the transport name string here.
*/
Status = MemoryAllocate( sizeof(DD_TCP_DEVICE_NAME), &pTransportName->Buffer );
if ( !NT_SUCCESS( Status ) )
goto badmalloc1;
wcscpy( pTransportName->Buffer, DD_TCP_DEVICE_NAME );
pTransportName->Length = sizeof(DD_TCP_DEVICE_NAME) - sizeof(UNICODE_NULL);
pTransportName->MaximumLength = pTransportName->Length + sizeof(UNICODE_NULL);
/*
* Allocate a transport address structure
*/
*pTransportAddressLength = sizeof(TRANSPORT_ADDRESS) +
sizeof(TDI_ADDRESS_IP);
Status = MemoryAllocate( *pTransportAddressLength, ppTransportAddress );
if ( !NT_SUCCESS( Status ) )
goto badmalloc2;
/*
* Initialize the static part of the transport address
*/
(*ppTransportAddress)->TAAddressCount = 1;
(*ppTransportAddress)->Address[0].AddressLength = sizeof(TDI_ADDRESS_IP);
(*ppTransportAddress)->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
pIpAddress = (PTDI_ADDRESS_IP)(*ppTransportAddress)->Address[0].Address;
pIpAddress->sin_port = htons( (USHORT)pTd->PortNumber );
RtlZeroMemory( pIpAddress->sin_zero, sizeof(pIpAddress->sin_zero) );
/*
* If a local address is specified, then use it.
*/
if ( pLocalAddress ) {
/*
* Skip over the address family(type) data (bytes 0&1) of the
* local address struct, and copy the remainder of the address
* directly to the Address field of the TransportAddress struct.
*/
ASSERT( *(PUSHORT)pLocalAddress == TDI_ADDRESS_TYPE_IP );
RtlCopyMemory( pIpAddress, &((PCHAR)pLocalAddress)[2], sizeof(TDI_ADDRESS_IP) );
/*
* There was no local address specified.
* In this case, we use the LanAdapter value from the PDPARAMS
* structure to lookup the corresponding IP address.
*/
} else if ( (Lana = pTd->Params.Network.LanAdapter) ) {
ULONG in_addr;
/*
* Get Local Address Information
*/
Status = _TcpGetTransportAddress( pTd, Lana, &in_addr );
if ( !NT_SUCCESS( Status ) )
goto badadapterdata;
pIpAddress->in_addr = in_addr;
/*
* No LanAdapter value was specified, so use the wildcard address (zero)
*/
} else {
pIpAddress->in_addr = 0;
}
return( STATUS_SUCCESS );
/*=============================================================================
== Error returns
=============================================================================*/
badadapterdata:
MemoryFree( *ppTransportAddress );
badmalloc2:
MemoryFree( pTransportName->Buffer );
badmalloc1:
return( Status );
}
/*****************************************************************************
*
* TdiDeviceBuildWildcardAddress
*
* Build a wildcard Address for this protocol.
*
* ENTRY:
*
* pTd (input)
* pointer to TD data structure
* ppWildcardAddress (output)
* pointer to location to return TRANSPORT_ADDRESS structure
* NOTE: the transport address buffer must be free'd by the caller
* pWildcardAddressLength (output)
* pointer to location to return TransportAddress length
*
* EXIT:
* STATUS_SUCCESS - Success
*
****************************************************************************/
NTSTATUS
TdiDeviceBuildWildcardAddress(
PTD pTd,
PTRANSPORT_ADDRESS *ppWildcardAddress,
PULONG pWildcardAddressLength
)
{
PTDI_ADDRESS_IP pIpAddress;
NTSTATUS Status;
/*
* Allocate a transport address structure
*/
*pWildcardAddressLength = sizeof(TRANSPORT_ADDRESS) +
sizeof(TDI_ADDRESS_IP);
Status = MemoryAllocate( *pWildcardAddressLength, ppWildcardAddress );
if ( !NT_SUCCESS( Status ) )
return( Status );
/*
* Initialize the static part of the transport address
*/
(*ppWildcardAddress)->TAAddressCount = 1;
(*ppWildcardAddress)->Address[0].AddressLength = sizeof(TDI_ADDRESS_IP);
(*ppWildcardAddress)->Address[0].AddressType = TDI_ADDRESS_TYPE_IP;
pIpAddress = (PTDI_ADDRESS_IP)(*ppWildcardAddress)->Address[0].Address;
pIpAddress->sin_port = 0;
pIpAddress->in_addr = 0;
RtlZeroMemory( pIpAddress->sin_zero, sizeof(pIpAddress->sin_zero) );
return( STATUS_SUCCESS );
}
/*****************************************************************************
*
* TdiDeviceWaitForDatagramConnection
*
* Wait for a datagram connection request, validate it,
* and return the remote transport address of the connection.
*
* ENTRY:
*
* pTd (input)
* pointer to TD data structure
* pFileObject (input)
* pointer to file object to wait for a connection on
* ppRemoteAddress (output)
* pointer to location to return TRANSPORT_ADDRESS structure
* NOTE: the transport address buffer must be free'd by the caller
* pRemoteAddressLength (output)
* pointer to location to return RemoteAddress length
*
* EXIT:
* STATUS_SUCCESS - Success
*
****************************************************************************/
NTSTATUS
TdiDeviceWaitForDatagramConnection(
PTD pTd,
PFILE_OBJECT pFileObject,
PDEVICE_OBJECT pDeviceObject,
PTRANSPORT_ADDRESS *ppRemoteAddress,
PULONG pRemoteAddressLength
)
{
return( STATUS_NOT_SUPPORTED );
}
/*****************************************************************************
*
* TdiDeviceCompleteDatagramConnection
*
* Do any final work to complete a datagram connection.
*
* ENTRY:
*
* pTd (input)
* pointer to TD data structure
* pFileObject (input)
* pointer to file object for this connection
*
* EXIT:
* STATUS_SUCCESS - Success
*
****************************************************************************/
NTSTATUS
TdiDeviceCompleteDatagramConnection(
PTD pTd,
PFILE_OBJECT pFileObject,
PDEVICE_OBJECT pDeviceObject,
PTRANSPORT_ADDRESS pRemoteAddress,
ULONG RemoteAddressLength
)
{
return( STATUS_NOT_SUPPORTED );
}
/*******************************************************************************
*
* TdiDeviceConnectionSend
*
* Initialize host module data structure
* -- this structure gets sent to the client
*
*
* ENTRY:
* pTd (input)
* Pointer to td data structure
*
* EXIT:
* STATUS_SUCCESS - no error
*
******************************************************************************/
NTSTATUS
TdiDeviceConnectionSend( PTD pTd )
{
PCLIENTMODULES pClient;
/*
* Get pointer to client structure
*/
pClient = pTd->pClient;
/*
* Initialize Td host module structure
*/
pClient->TdVersionL = VERSION_HOSTL_TDTCP;
pClient->TdVersionH = VERSION_HOSTH_TDTCP;
pClient->TdVersion = VERSION_HOSTH_TDTCP;
return( STATUS_SUCCESS );
}
/*******************************************************************************
*
* TdiDeviceReadComplete
*
* Do any read complete processing
*
*
* ENTRY:
* pTd (input)
* Pointer to td data structure
* pBuffer (input)
* Pointer to input buffer
* pByteCount (input/output)
* Pointer to location containing byte count read
*
* EXIT:
* STATUS_SUCCESS - no error
*
******************************************************************************/
NTSTATUS
TdiDeviceReadComplete( PTD pTd, PUCHAR pBuffer, PULONG pByteCount )
{
return( STATUS_SUCCESS );
}
/*******************************************************************************
*
* _TcpGetTransportAddress
*
* Get TCP transport address for a given LanAdapter number
*
*
* ENTRY:
* pTd (input)
* pointer to TD data structure
* Lana (input)
* Lan Adapter number, 1-based based on the tscc.msc UI ordering.
* pIpAddr (output)
* address to return IP address
*
* EXIT:
* STATUS_SUCCESS - no error
*
******************************************************************************/
#if 0 // replacement below
NTSTATUS _TcpGetTransportAddress(PTD pTd, int Lana, PULONG pIpAddr)
{
HANDLE KeyHandle;
UNICODE_STRING RouteString;
PWCHAR pInterfaceGuid;
NTSTATUS Status;
unsigned Len;
PWCHAR Str;
/*
* Open the Tcp Linkage key
*/
Status = _OpenRegKey( &KeyHandle, REGISTRY_TCP_LINKAGE );
if ( !NT_SUCCESS( Status ) )
goto badopen;
/*
* Alloc and read in the linkage route multi-string.
*
* This is of the form (including the double quotes):
* "{<guid>}"\0"{<guid>}"\0"NdisWanIp"\0\0
*
* Each of the GUIDs is a link to the adapter interface keys
* stored at HKLM\System\CCS\Services\tcpip\Parameters\Interfaces,
* inside of which is the IP address information.
*/
RouteString.Length = 0;
RouteString.MaximumLength = 0;
RouteString.Buffer = NULL;
Status = _GetRegMultiSZValue( KeyHandle, L"Route", &RouteString );
ZwClose( KeyHandle );
if ( !NT_SUCCESS( Status ) )
goto badvalue;
/*
* Find the interface GUID that corresponds to the specified UI LANA
* index. The LANA index corresponds to the registry ordering of the
* interfaces, skipping the PPP interface(s). From the way the
* registry looks PPP interfaces do not have GUIDs specified in
* the Linkage key, so we skip the non-GUID entries.
*/
if (RouteString.Length < (2 * sizeof(WCHAR))) {
Status = STATUS_DEVICE_DOES_NOT_EXIST;
goto PostAllocRouteString;
}
Len = RouteString.Length;
Str = RouteString.Buffer;
for (;;) {
// Check current string to see if it's a GUID (it must start with an
// open brace after initial double-quote).
if (Str[1] == L'{') {
// Have we found it?
if (Lana == 1)
break;
Lana--;
}
// Skip through current string past NULL.
while (Len >= sizeof(WCHAR)) {
Len -= sizeof(WCHAR);
if (*Str++ == UNICODE_NULL)
break;
}
// Check for index out of range.
if (Len < (2 * sizeof(UNICODE_NULL))) {
Status = STATUS_DEVICE_DOES_NOT_EXIST;
goto PostAllocRouteString;
}
}
if (Len >= (2 * sizeof(UNICODE_NULL))) {
ULONG DhcpEnabled;
UNICODE_STRING IpAddrString;
UNICODE_STRING KeyString;
WCHAR KeyName[256];
char AnsiBuf[256];
// Skip the initial double quote, and change the ending quote to a
// NULL.
Str++;
pInterfaceGuid = Str;
while (*Str != L'\"')
Str++;
*Str = L'\0';
/*
* Use the GUID to look up the interface IP info.
*/
// We open HKLM\System\CCS\Services\tcpip\Parameters\Interfaces\<GUID>
// to get to the DHCP and IP address information.
KeyString.Length = 0;
KeyString.MaximumLength = sizeof(KeyName);
KeyString.Buffer = KeyName;
RtlAppendUnicodeToString(&KeyString, REGISTRY_TCP_INTERFACES);
RtlAppendUnicodeToString(&KeyString, pInterfaceGuid);
Status = _OpenRegKey(&KeyHandle, KeyName);
if (!NT_SUCCESS(Status))
goto PostAllocRouteString;
// Query the "EnableDHCP" value.
Status = _GetRegDWORDValue(KeyHandle, L"EnableDHCP", &DhcpEnabled);
if (!NT_SUCCESS(Status)) {
ZwClose(KeyHandle);
goto PostAllocRouteString;
}
IpAddrString.Length = 0;
IpAddrString.MaximumLength = 0;
IpAddrString.Buffer = NULL;
if (DhcpEnabled) {
ULONG ValueType;
// If DHCP is enabled for this device, then we query the current
// IP address from the "DhcpIPAddress" value.
Status = _GetRegSZValue(KeyHandle, L"DhcpIPAddress",
&IpAddrString, &ValueType);
}
else {
// DHCP is not enabled for this device, so we query the
// IP address from the "IPAddress" value.
Status = _GetRegMultiSZValue(KeyHandle, L"IPAddress",
&IpAddrString);
}
ZwClose(KeyHandle);
if (!NT_SUCCESS(Status))
goto PostAllocRouteString;
// Convert IP address from Unicode to ansi to a ULONG.
_UnicodeToAnsi(AnsiBuf, sizeof(AnsiBuf) - 1, IpAddrString.Buffer);
*pIpAddr = _inet_addr(AnsiBuf);
MemoryFree(IpAddrString.Buffer);
}
else {
Status = STATUS_DEVICE_DOES_NOT_EXIST;
goto PostAllocRouteString;
}
PostAllocRouteString:
MemoryFree(RouteString.Buffer);
badvalue:
badopen:
return Status;
}
#endif
/*******************************************************************************
*
* _TcpGetTransportAddress(2)
*
* Get TCP transport address for a given LanAdapter number
*
*
* ENTRY:
* pTd (input)
* pointer to TD data structure
* Lana (input)
* Lan Adapter number, 1-based based on the tscc.msc UI ordering.
* pIpAddr (output)
* address to return IP address
*
* EXIT:
* STATUS_SUCCESS - no error
*
******************************************************************************/
NTSTATUS _TcpGetTransportAddress(PTD pTd, int Lana, PULONG pIpAddr)
{
HANDLE KeyHandle;
UNICODE_STRING RouteString;
PWCHAR pInterfaceGuid;
NTSTATUS Status;
unsigned Len;
PWCHAR Str;
RtlInitUnicodeString( &RouteString , NULL );
GetGUID( &RouteString , Lana );
Len = RouteString.Length;
Str = RouteString.Buffer;
KdPrint( ( "TDTCP: _TcpGetTransportAddress Length = %d GUID = %ws\n" , Len , Str ) );
if( Str == NULL )
{
return STATUS_DEVICE_DOES_NOT_EXIST;
}
if (Len >= (2 * sizeof(UNICODE_NULL))) {
ULONG DhcpEnabled;
UNICODE_STRING IpAddrString;
UNICODE_STRING KeyString;
WCHAR KeyName[256];
char AnsiBuf[256];
pInterfaceGuid = Str;
// Skip the initial double quote, and change the ending quote to a
// NULL.
/*
Str++;
pInterfaceGuid = Str;
while (*Str != L'\"')
Str++;
*Str = L'\0';
*/
/*
* Use the GUID to look up the interface IP info.
*/
// We open HKLM\System\CCS\Services\tcpip\Parameters\Interfaces\<GUID>
// to get to the DHCP and IP address information.
KeyString.Length = 0;
KeyString.MaximumLength = sizeof(KeyName);
KeyString.Buffer = KeyName;
RtlAppendUnicodeToString(&KeyString, REGISTRY_TCP_INTERFACES);
RtlAppendUnicodeToString(&KeyString, pInterfaceGuid);
Status = _OpenRegKey(&KeyHandle, KeyName);
if (!NT_SUCCESS(Status))
goto PostAllocRouteString;
// Query the "EnableDHCP" value.
Status = _GetRegDWORDValue(KeyHandle, L"EnableDHCP", &DhcpEnabled);
if (!NT_SUCCESS(Status)) {
ZwClose(KeyHandle);
goto PostAllocRouteString;
}
IpAddrString.Length = 0;
IpAddrString.MaximumLength = 0;
IpAddrString.Buffer = NULL;
if (DhcpEnabled) {
ULONG ValueType;
// If DHCP is enabled for this device, then we query the current
// IP address from the "DhcpIPAddress" value.
Status = _GetRegSZValue(KeyHandle, L"DhcpIPAddress",
&IpAddrString, &ValueType);
}
else {
// DHCP is not enabled for this device, so we query the
// IP address from the "IPAddress" value.
Status = _GetRegMultiSZValue(KeyHandle, L"IPAddress",
&IpAddrString);
}
ZwClose(KeyHandle);
if (!NT_SUCCESS(Status))
goto PostAllocRouteString;
// Convert IP address from Unicode to ansi to a ULONG.
_UnicodeToAnsi(AnsiBuf, sizeof(AnsiBuf) - 1, IpAddrString.Buffer);
*pIpAddr = _inet_addr(AnsiBuf);
MemoryFree(IpAddrString.Buffer);
}
else {
Status = STATUS_DEVICE_DOES_NOT_EXIST;
goto PostAllocRouteString;
}
PostAllocRouteString:
if( RouteString.Buffer != NULL )
{
MemoryFree(RouteString.Buffer);
}
return Status;
}
/*******************************************************************************
*
* _UnicodeToAnsi
*
* convert a UNICODE (WCHAR) string into an ANSI (CHAR) string
*
* ENTRY:
*
* pAnsiString (output)
* buffer to place ANSI string into
* lAnsiMax (input)
* maximum number of characters to write into pAnsiString
* pUnicodeString (input)
* UNICODE string to convert
*
* EXIT:
* nothing (VOID)
*
******************************************************************************/
VOID
_UnicodeToAnsi(
CHAR * pAnsiString,
ULONG lAnsiMax,
WCHAR * pUnicodeString )
{
ULONG ByteCount;
NTSTATUS
RtlUnicodeToMultiByteN(
OUT PCH MultiByteString,
IN ULONG MaxBytesInMultiByteString,
OUT PULONG BytesInMultiByteString OPTIONAL,
IN PWCH UnicodeString,
IN ULONG BytesInUnicodeString);
RtlUnicodeToMultiByteN( pAnsiString, lAnsiMax, &ByteCount,
pUnicodeString,
((wcslen(pUnicodeString) + 1) << 1) );
}
/*
* Internet address interpretation routine.
* All the network library routines call this
* routine to interpret entries in the data bases
* which are expected to be an address.
* The value returned is in network order.
*/
unsigned long
_inet_addr(
IN const char *cp
)
/*++
Routine Description:
This function interprets the character string specified by the cp
parameter. This string represents a numeric Internet address
expressed in the Internet standard ".'' notation. The value
returned is a number suitable for use as an Internet address. All
Internet addresses are returned in network order (bytes ordered from
left to right).
Internet Addresses
Values specified using the "." notation take one of the following
forms:
a.b.c.d a.b.c a.b a
When four parts are specified, each is interpreted as a byte of data
and assigned, from left to right, to the four bytes of an Internet
address. Note that when an Internet address is viewed as a 32-bit
integer quantity on the Intel architecture, the bytes referred to
above appear as "d.c.b.a''. That is, the bytes on an Intel
processor are ordered from right to left.
Note: The following notations are only used by Berkeley, and nowhere
else on the Internet. In the interests of compatibility with their
software, they are supported as specified.
When a three part address is specified, the last part is interpreted
as a 16-bit quantity and placed in the right most two bytes of the
network address. This makes the three part address format
convenient for specifying Class B network addresses as
"128.net.host''.
When a two part address is specified, the last part is interpreted
as a 24-bit quantity and placed in the right most three bytes of the
network address. This makes the two part address format convenient
for specifying Class A network addresses as "net.host''.
When only one part is given, the value is stored directly in the
network address without any byte rearrangement.
Arguments:
cp - A character string representing a number expressed in the
Internet standard "." notation.
Return Value:
If no error occurs, inet_addr() returns an in_addr structure
containing a suitable binary representation of the Internet address
given. Otherwise, it returns the value INADDR_NONE.
--*/
{
register unsigned long val, base, n;
register char c;
unsigned long parts[4], *pp = parts;
#define INADDR_NONE 0xffffffff
#define htonl(x) ((((x) >> 24) & 0x000000FFL) | \
(((x) >> 8) & 0x0000FF00L) | \
(((x) << 8) & 0x00FF0000L) | \
(((x) << 24) & 0xFF000000L))
again:
/*
* Collect number up to ``.''.
* Values are specified as for C:
* 0x=hex, 0=octal, other=decimal.
*/
val = 0; base = 10;
if (*cp == '0') {
base = 8, cp++;
if (*cp == 'x' || *cp == 'X')
base = 16, cp++;
}
while (c = *cp) {
if (isdigit(c)) {
val = (val * base) + (c - '0');
cp++;
continue;
}
if (base == 16 && isxdigit(c)) {
val = (val << 4) + (c + 10 - (islower(c) ? 'a' : 'A'));
cp++;
continue;
}
break;
}
if (*cp == '.') {
/*
* Internet format:
* a.b.c.d
* a.b.c (with c treated as 16-bits)
* a.b (with b treated as 24 bits)
*/
/* GSS - next line was corrected on 8/5/89, was 'parts + 4' */
if (pp >= parts + 3) {
return ((unsigned long) -1);
}
*pp++ = val, cp++;
goto again;
}
/*
* Check for trailing characters.
*/
if (*cp && !isspace(*cp)) {
return (INADDR_NONE);
}
*pp++ = val;
/*
* Concoct the address according to
* the number of parts specified.
*/
n = (unsigned long)(pp - parts);
switch ((int) n) {
case 1: /* a -- 32 bits */
val = parts[0];
break;
case 2: /* a.b -- 8.24 bits */
if ((parts[0] > 0xff) || (parts[1] > 0xffffff)) {
return(INADDR_NONE);
}
val = (parts[0] << 24) | (parts[1] & 0xffffff);
break;
case 3: /* a.b.c -- 8.8.16 bits */
if ((parts[0] > 0xff) || (parts[1] > 0xff) ||
(parts[2] > 0xffff)) {
return(INADDR_NONE);
}
val = (parts[0] << 24) | ((parts[1] & 0xff) << 16) |
(parts[2] & 0xffff);
break;
case 4: /* a.b.c.d -- 8.8.8.8 bits */
if ((parts[0] > 0xff) || (parts[1] > 0xff) ||
(parts[2] > 0xff) || (parts[3] > 0xff)) {
return(INADDR_NONE);
}
val = (parts[0] << 24) | ((parts[1] & 0xff) << 16) |
((parts[2] & 0xff) << 8) | (parts[3] & 0xff);
break;
default:
return (INADDR_NONE);
}
val = htonl(val);
return (val);
}
/*****************************************************************************
*
* _TcpSetNagle
*
* This function turns on, or off the NAGLE algorithum.
*
* ENTRY:
* Param1 (input/output)
* Comments
*
* EXIT:
* STATUS_SUCCESS - no error
*
****************************************************************************/
NTSTATUS
_TcpSetNagle(
IN PFILE_OBJECT pFileObject,
IN PDEVICE_OBJECT DeviceObject,
IN BOOLEAN Flag
)
{
NTSTATUS Status;
ULONG Value;
if( Flag ) {
Value = FALSE;
}
else {
Value = TRUE;
}
Status = _TdiTcpSetInformation(
pFileObject,
DeviceObject,
CO_TL_ENTITY,
INFO_CLASS_PROTOCOL,
INFO_TYPE_CONNECTION,
TCP_SOCKET_NODELAY,
&Value,
sizeof(Value),
TRUE
);
DBGPRINT(("_TcpSetNagle: Flag 0x%x, Result 0x%x\n",Flag,Status));
return( Status );
}
NTSTATUS
_TdiTcpSetInformation (
IN PFILE_OBJECT pFileObject,
IN PDEVICE_OBJECT DeviceObject,
IN ULONG Entity,
IN ULONG Class,
IN ULONG Type,
IN ULONG Id,
IN PVOID Value,
IN ULONG ValueLength,
IN BOOLEAN WaitForCompletion)
/*++
NOTE: This is a modified routine from WSHTCPIP.C
Routine Description:
Performs a TDI action to the TCP/IP driver. A TDI action translates
into a streams T_OPTMGMT_REQ.
Arguments:
TdiConnectionObjectHandle - a TDI connection object on which to perform
the TDI action.
Entity - value to put in the tei_entity field of the TDIObjectID
structure.
Class - value to put in the toi_class field of the TDIObjectID
structure.
Type - value to put in the toi_type field of the TDIObjectID
structure.
Id - value to put in the toi_id field of the TDIObjectID structure.
Value - a pointer to a buffer to set as the information.
ValueLength - the length of the buffer.
Return Value:
NTSTATUS code
--*/
{
NTSTATUS status;
PTCP_REQUEST_SET_INFORMATION_EX pSetInfoEx;
PIO_STATUS_BLOCK pIOSB;
// Allocate space to hold the TDI set information buffers and the IO
// status block. Note the IOSB is a required field for the lower
// layers despite the OPTIONAL label in CtxDeviceIoControlFile.
status = MemoryAllocate(sizeof(*pSetInfoEx) + ValueLength +
sizeof(IO_STATUS_BLOCK), &pIOSB);
if (status == STATUS_SUCCESS) {
// The SetInfoEx is after the I/O status block in this alloc.
pSetInfoEx = (PTCP_REQUEST_SET_INFORMATION_EX)(pIOSB + 1);
// Initialize the TDI information buffers.
pSetInfoEx->ID.toi_entity.tei_entity = Entity;
pSetInfoEx->ID.toi_entity.tei_instance = TL_INSTANCE;
pSetInfoEx->ID.toi_class = Class;
pSetInfoEx->ID.toi_type = Type;
pSetInfoEx->ID.toi_id = Id;
RtlCopyMemory(pSetInfoEx->Buffer, Value, ValueLength);
pSetInfoEx->BufferSize = ValueLength;
// Make the actual TDI action call. The Streams TDI mapper will
// translate this into a TPI option management request for us and
// give it to TCP/IP.
status = CtxDeviceIoControlFile(pFileObject,
IOCTL_TCP_SET_INFORMATION_EX, pSetInfoEx,
sizeof(*pSetInfoEx) + ValueLength, NULL, 0, FALSE, NULL,
pIOSB, NULL);
MemoryFree(pIOSB);
}
#if DBG
if (!NT_SUCCESS(status)) {
DBGPRINT(("_TdiTcpSetInformation: Error 0x%x\n",status));
}
#endif
return status;
}