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.
1372 lines
39 KiB
1372 lines
39 KiB
/****************************************************************************/
|
|
// 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 TdiDeviceQueryLocalAddress( PTD, 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 );
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* TdiDeviceQueryLocalAddress
|
|
*
|
|
* Query Transport Address given an optional ICA_STACK_ADDRESS,
|
|
* or the Lana value from the pTd->Params structure.
|
|
*
|
|
* ENTRY:
|
|
*
|
|
* pTd (input)
|
|
* pointer to TD data structure
|
|
* 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
|
|
TdiDeviceQueryLocalAddress(
|
|
PTD pTd,
|
|
PTRANSPORT_ADDRESS *ppTransportAddress,
|
|
PULONG pTransportAddressLength
|
|
)
|
|
{
|
|
PTDI_ADDRESS_IP pIpAddress;
|
|
int Lana;
|
|
NTSTATUS Status;
|
|
|
|
/*
|
|
* Allocate a transport address structure
|
|
*/
|
|
*pTransportAddressLength = sizeof(TRANSPORT_ADDRESS) +
|
|
sizeof(TDI_ADDRESS_IP);
|
|
Status = MemoryAllocate( *pTransportAddressLength, ppTransportAddress );
|
|
if ( !NT_SUCCESS( Status ) )
|
|
goto badmalloc;
|
|
|
|
/*
|
|
* 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) );
|
|
|
|
//In this case, we use the LanAdapter value from the PDPARAMS
|
|
// structure to lookup the corresponding IP address.
|
|
|
|
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 );
|
|
*ppTransportAddress = NULL;
|
|
|
|
badmalloc:
|
|
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;
|
|
}
|
|
|