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

814 lines
22 KiB
C
Raw Permalink Normal View History

2020-09-26 03:20:57 -05:00
/*************************************************************************
*
* tdspx.c
*
* Copyright 1998, Microsoft
*
*************************************************************************/
#include <ntddk.h>
#include <tdi.h>
#include <isnkrnl.h>
#include <ndis.h>
#include <wsnwlink.h>
#include <winstaw.h>
#define _DEFCHARINFO_
#include <icadd.h>
#include <ctxdd.h>
#include <sdapi.h>
#include <td.h>
#include "tdtdi.h"
#include "tdspx.h"
#ifdef _HYDRA_
// This becomes the device name
PWCHAR ModuleName = L"tdspx";
#endif
#define REG_IPX_Linkage \
L"\\Registry\\Machine\\System\\CurrentControlSet\\Services\\NwlnkIpx\\Linkage"
#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
=============================================================================*/
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 );
NTSTATUS _OpenRegKey(PHANDLE, PWCHAR);
NTSTATUS _GetRegMultiSZValue(HANDLE ,PWCHAR,PUNICODE_STRING );
VOID GetGUID(OUT PUNICODE_STRING, IN int);
/*=============================================================================
== External Functions Referenced
=============================================================================*/
NTSTATUS MemoryAllocate( ULONG, PVOID * );
VOID MemoryFree( PVOID );
/*=============================================================================
== Internal Functions Defined
=============================================================================*/
NTSTATUS _IpxGetTransportAddress( PTD, int, PULONG, PUCHAR );
NTSTATUS _IPXGetAdapterNumber( int Lana, int * AdpNum );
#if DBG
VOID
DumpIpxAddress(
PTRANSPORT_ADDRESS p,
ULONG Len
);
#endif
/*=============================================================================
== Global variables
=============================================================================*/
/*
* Define variables used by afdcommon code
*/
USHORT TdiDeviceEndpointType = TdiConnectionStream;
USHORT TdiDeviceAddressType = TDI_ADDRESS_TYPE_IPX;
USHORT TdiDeviceInBufHeader = 0;
// ULONG TdiDeviceMaxTransportAddressLength = sizeof(TA_IPX_ADDRESS);
/*******************************************************************************
*
* 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
)
{
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_IPX pIpxAddress;
int Lana;
NTSTATUS Status;
/*
* For SPX, the transport device name is fixed,
* so just allocate and initialize the transport name string here.
*/
Status = MemoryAllocate( sizeof(DD_SPX_DEVICE_NAME), &pTransportName->Buffer );
if ( !NT_SUCCESS( Status ) ) {
DBGPRINT(("TdiDeviceBuildTransportNameAndAddress: SPX Could not allocate memory\n"));
goto badmalloc1;
}
wcscpy( pTransportName->Buffer, DD_SPX_DEVICE_NAME );
pTransportName->Length = sizeof(DD_SPX_DEVICE_NAME) - sizeof(UNICODE_NULL);
pTransportName->MaximumLength = pTransportName->Length + sizeof(UNICODE_NULL);
/*
* Allocate a transport address structure
*/
*pTransportAddressLength = sizeof(TRANSPORT_ADDRESS) +
sizeof(TDI_ADDRESS_IPX);
Status = MemoryAllocate( *pTransportAddressLength, ppTransportAddress );
if ( !NT_SUCCESS( Status ) ) {
DBGPRINT(("TdiDeviceBuildTransportNameAndAddress: SPX Could not allocate memory\n"));
goto badmalloc2;
}
/*
* Initialize the static part of the transport address
*/
(*ppTransportAddress)->TAAddressCount = 1;
(*ppTransportAddress)->Address[0].AddressLength = sizeof(TDI_ADDRESS_IPX);
(*ppTransportAddress)->Address[0].AddressType = TDI_ADDRESS_TYPE_IPX;
pIpxAddress = (PTDI_ADDRESS_IPX)(*ppTransportAddress)->Address[0].Address;
pIpxAddress->Socket = htons( CITRIX_SPX_SOCKET );
/*
* 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_IPX );
RtlCopyMemory( pIpxAddress, &((PCHAR)pLocalAddress)[2], sizeof(TDI_ADDRESS_IPX) );
TRACE1(("TDSPX: TdiDeviceBuildTransportAddress: Local address:\n"));
/*
* There was no local address specified.
* In this case, we use the LanAdapter value from the PDPARAMS
* structure to lookup the corresponding IPX address.
*/
} else if ( (Lana = pTd->Params.Network.LanAdapter) ) {
/*
* Get Local Address Information
*/
Status = _IpxGetTransportAddress( pTd, Lana,
&pIpxAddress->NetworkAddress,
pIpxAddress->NodeAddress );
if ( !NT_SUCCESS( Status ) ) {
DBGPRINT(("TDSPX: TdiDeviceBuildTransportAddress: Bad Lana 0x%x\n",Lana));
goto badadapterdata;
}
TRACE1(("TDSPX: TdiDeviceBuildTransportAddress: Found address for Lana 0x%x\n",Lana));
/*
* No LanAdapter value was specified, so use the wildcard address (zero)
*/
} else {
DBGPRINT(("TDSPX: TdiDeviceBuildTransportAddress: Wildcard address"));
pIpxAddress->NetworkAddress = 0;
RtlZeroMemory( pIpxAddress->NodeAddress,
sizeof(pIpxAddress->NodeAddress) );
}
#if DBGTRACE
DumpIpxAddress( *ppTransportAddress, *pTransportAddressLength );
#endif
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_IPX pIpxAddress;
NTSTATUS Status;
/*
* Allocate a transport address structure
*/
*pWildcardAddressLength = sizeof(TRANSPORT_ADDRESS) +
sizeof(TDI_ADDRESS_IPX);
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_IPX);
(*ppWildcardAddress)->Address[0].AddressType = TDI_ADDRESS_TYPE_IPX;
pIpxAddress = (PTDI_ADDRESS_IPX)(*ppWildcardAddress)->Address[0].Address;
pIpxAddress->NetworkAddress = 0;
RtlZeroMemory( pIpxAddress->NodeAddress,
sizeof(pIpxAddress->NodeAddress) );
pIpxAddress->Socket = 0;
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 pTransportAddress,
ULONG TransportAddressLength
)
{
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_TDSPX;
pClient->TdVersionH = VERSION_HOSTH_TDSPX;
pClient->TdVersion = VERSION_HOSTH_TDSPX;
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 );
}
/*******************************************************************************
*
* _IpxGetTransportAddress
*
* Get IPX transport address for a given LanAdapter number
*
*
* ENTRY:
* pTd (input)
* pointer to TD data structure
* Lana (input)
* Lan Adapter number
* pNetworkAddress (output)
* pointer to location to return NetworkAddress
* pNodeAddress (output)
* pointer to location to return NodeAddress
*
*
* EXIT:
* STATUS_SUCCESS - no error
*
******************************************************************************/
NTSTATUS
_IpxGetTransportAddress(
PTD pTd,
int Lana,
PULONG pNetworkAddress,
PUCHAR pNodeAddress
)
{
OBJECT_ATTRIBUTES objectAttributes;
IO_STATUS_BLOCK ioStatusBlock;
UNICODE_STRING nameString;
HANDLE IPXHandle;
ULONG tdiBufferLength;
PSTREAMS_TDI_ACTION tdiBuffer;
ULONG cmd;
PIPX_ADDRESS_DATA pIpxAddressData;
PFILE_OBJECT pFileObject;
NTSTATUS Status;
int IpxAdapterNum = 0;
/*
* Open a Handle to the IPX driver.
*/
RtlInitUnicodeString( &nameString, DD_IPX_DEVICE_NAME );
InitializeObjectAttributes(
&objectAttributes,
&nameString,
OBJ_CASE_INSENSITIVE,
(HANDLE) NULL,
(PSECURITY_DESCRIPTOR) NULL
);
Status = ZwCreateFile( &IPXHandle,
SYNCHRONIZE | FILE_READ_DATA | FILE_WRITE_DATA,
&objectAttributes,
&ioStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
FILE_SHARE_READ | FILE_SHARE_WRITE,
FILE_OPEN_IF,
0,
NULL,
0
);
if ( !NT_SUCCESS( Status ) )
return( Status );
/*
* Allocate a TDI buffer to do the IOCTL.
*/
tdiBufferLength = sizeof(STREAMS_TDI_ACTION) + sizeof(ULONG) +
sizeof(IPX_ADDRESS_DATA);
Status = MemoryAllocate( tdiBufferLength, &tdiBuffer );
if ( !NT_SUCCESS( Status ) ) {
ZwClose( IPXHandle );
return( Status );
}
// Get IPX Adapter Num from winstation Lana ID
Status = _IPXGetAdapterNumber( Lana, &IpxAdapterNum);
if ( !NT_SUCCESS( Status ) ) {
ZwClose( IPXHandle );
return( Status );
}
/*
* Fill in the tdiBuffer header
*/
RtlMoveMemory( &tdiBuffer->Header.TransportId, "MISN", 4 );
// use the following since we opened a control channel above
tdiBuffer->DatagramOption = NWLINK_OPTION_CONTROL;
/**
Fill out the buffer, the buffer looks like this:
ULONG cmd
data passed.
**/
cmd = MIPX_GETCARDINFO;
memcpy( tdiBuffer->Buffer, &cmd, sizeof(ULONG));
tdiBuffer->BufferLength = sizeof(ULONG) + sizeof(IPX_ADDRESS_DATA);
pIpxAddressData = (PIPX_ADDRESS_DATA)(tdiBuffer->Buffer + sizeof(ULONG));
pIpxAddressData->adapternum = IpxAdapterNum;
Status = ObReferenceObjectByHandle( IPXHandle,
0,
NULL,
KernelMode,
(PVOID *)&pFileObject,
NULL
);
ASSERT( Status == STATUS_SUCCESS );
Status = CtxDeviceIoControlFile( pFileObject,
IOCTL_TDI_ACTION,
NULL,
0,
tdiBuffer,
tdiBufferLength,
FALSE,
NULL,
&ioStatusBlock,
NULL
);
ObDereferenceObject( pFileObject );
ZwClose( IPXHandle );
if ( Status == STATUS_SUCCESS ) {
RtlCopyMemory( pNetworkAddress, pIpxAddressData->netnum,
sizeof(pIpxAddressData->netnum) );
RtlCopyMemory( pNodeAddress, pIpxAddressData->nodenum,
sizeof(pIpxAddressData->nodenum) );
}
return( Status );
}
#if DBG
VOID
DumpIpxAddress(
PTRANSPORT_ADDRESS p,
ULONG Len
)
{
ULONG j;
LONG i;
PTDI_ADDRESS_IPX Ipx;
DbgPrint("TAAddressCount %d, TotalLen %d\n",p->TAAddressCount,Len);
for( i=0; i < p->TAAddressCount; i++ ) {
DbgPrint("AddressLength %d, AddressType %d\n",p->Address[i].AddressLength,p->Address[i].AddressType);
Ipx = (PTDI_ADDRESS_IPX)&p->Address[i].Address[0];
DbgPrint("Network 0x%x Socket 0x%x\n",Ipx->NetworkAddress,Ipx->Socket);
for( j=0; j < 6; j++ ) {
DbgPrint("%x:",Ipx->NodeAddress[j]);
}
DbgPrint("\n\n");
}
}
#endif
NTSTATUS
_IPXGetAdapterNumber(
int Lana,
int * AdpNum
)
/*++
Routine Description:
Get the IPX Lan Adapter number using the instation Lana ID index
Arguments:
Lana - IN the winstation Lana ID index
AdpNum - OUT the IPX Lana Adapter num
Return Value:
return nt status
--*/
{
NTSTATUS Status;
int AdapterNum;
UNICODE_STRING RouteString;
UNICODE_STRING NameString;
HANDLE KeyHandle = NULL;
PWSTR RouteStr, Str;
unsigned RouteLen, Len;
/*
* Convert winstation Lana_ID to Network Adapter number
*/
RtlInitUnicodeString( &RouteString , NULL );
GetGUID( &RouteString , Lana );
RouteLen = RouteString.Length;
RouteStr = RouteString.Buffer;
AdapterNum =0;
#if DBG
KdPrint( ( "TDIPX: _TcpGetTransportAddress Length = %d GUID = %ws\n" , RouteLen, RouteStr ) );
#endif
if (RouteLen < (2 * sizeof(UNICODE_NULL))) {
return( STATUS_DEVICE_DOES_NOT_EXIST );
}
RtlInitUnicodeString( &NameString, NULL );
Status = _OpenRegKey( &KeyHandle, REG_IPX_Linkage );
if ( !NT_SUCCESS( Status ) )
return Status;
NameString.Length = 0;
NameString.MaximumLength = 0;
NameString.Buffer = NULL;
Status = _GetRegMultiSZValue( KeyHandle, L"Route", &NameString );
ZwClose( KeyHandle );
if ( !NT_SUCCESS( Status ) )
return Status;
if (NameString.Length < (2 * sizeof(WCHAR))) {
return(STATUS_DEVICE_DOES_NOT_EXIST);
}
Len = NameString.Length;
Str = NameString.Buffer;
Status = STATUS_DEVICE_DOES_NOT_EXIST;
AdapterNum = 0;
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'{') {
if ( wcsncmp( (PWSTR) &Str[1],RouteStr, wcslen(RouteStr)-1) == 0) {
#if DBG
KdPrint( ( "TDIPX: _TcpGetTransportAddress: Get Lan Adapter Number = %i\n",AdapterNum ) );
#endif
Status = STATUS_SUCCESS;
break;
}
else {
// KdPrint( ( "TDIPX: _TcpGetTransportAddress, No this lana Adapter = %i\n",AdapterNum ) );
AdapterNum ++;
}
}
// 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))) {
break;
}
}
if ( !NT_SUCCESS( Status ) )
return Status;
*AdpNum = AdapterNum;
return STATUS_SUCCESS;
}