windows-nt/Source/XPSP1/NT/net/nwlink/spx/spxutils.c
2020-09-26 16:20:57 +08:00

485 lines
8.7 KiB
C

/*++
Copyright (c) 1989-1993 Microsoft Corporation
Module Name:
spxutils.c
Abstract:
This contains all utility routines for the ISN SPX module.
Revision History:
--*/
#include "precomp.h"
#pragma hdrstop
// Define module number for event logging entries
#define FILENUM SPXUTILS
UINT
SpxUtilWstrLength(
IN PWSTR Wstr
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
UINT length = 0;
while (*Wstr++)
{
length += sizeof(WCHAR);
}
return length;
}
LONG
SpxRandomNumber(
VOID
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
LARGE_INTEGER Li;
static LONG seed = 0;
// Return a positive pseudo-random number; simple linear congruential
// algorithm. ANSI C "rand()" function.
if (seed == 0)
{
KeQuerySystemTime(&Li);
seed = Li.LowPart;
}
seed *= (0x41C64E6D + 0x3039);
return (seed & 0x7FFFFFFF);
}
NTSTATUS
SpxUtilGetSocketType(
PUNICODE_STRING RemainingFileName,
PBYTE SocketType
)
/*++
Routine Description:
For PROTO_SPX, i'd return a device name from the dll of the form
\Device\IsnSpx\SpxStream (for SOCK_STREAM) or
\Device\IsnSpx\Spx (for SOCK_SEQPKT)
and for PROTO_SPXII (the more common case we hope, even if
internally we degrade to SPX1 cause of the remote client's
limitations)
\Device\IsnSpx\Stream (for SOCK_STREAM) or
\Device\IsnSpx (for SOCK_SEQPKT)
Arguments:
Return Value:
--*/
{
NTSTATUS status = STATUS_SUCCESS;
UNICODE_STRING typeString;
*SocketType = SOCKET2_TYPE_SEQPKT;
// Check for the socket type
do
{
if (RemainingFileName->Length == 0)
{
break;
}
if ((UINT)RemainingFileName->Length ==
SpxUtilWstrLength(SOCKET1STREAM_SUFFIX))
{
RtlInitUnicodeString(&typeString, SOCKET1STREAM_SUFFIX);
// Case insensitive compare
if (RtlEqualUnicodeString(&typeString, RemainingFileName, TRUE))
{
*SocketType = SOCKET1_TYPE_STREAM;
break;
}
}
if ((UINT)RemainingFileName->Length ==
SpxUtilWstrLength(SOCKET1_SUFFIX))
{
RtlInitUnicodeString(&typeString, SOCKET1_SUFFIX);
// Case insensitive compare
if (RtlEqualUnicodeString(&typeString, RemainingFileName, TRUE))
{
*SocketType = SOCKET1_TYPE_SEQPKT;
break;
}
}
if ((UINT)RemainingFileName->Length ==
SpxUtilWstrLength(SOCKET2STREAM_SUFFIX))
{
RtlInitUnicodeString(&typeString, SOCKET2STREAM_SUFFIX);
// Case insensitive compare
if (RtlEqualUnicodeString(&typeString, RemainingFileName, TRUE))
{
*SocketType = SOCKET2_TYPE_STREAM;
break;
}
}
status = STATUS_NO_SUCH_DEVICE;
} while (FALSE);
return(status);
}
#define ONE_MS_IN_100ns -10000L // 1ms in 100ns units
VOID
SpxSleep(
IN ULONG TimeInMs
)
/*++
Routine Description:
Arguments:
Return Value:
--*/
{
KTIMER SleepTimer;
ASSERT (KeGetCurrentIrql() == LOW_LEVEL);
KeInitializeTimer(&SleepTimer);
KeSetTimer(&SleepTimer,
RtlConvertLongToLargeInteger(TimeInMs * ONE_MS_IN_100ns),
NULL);
KeWaitForSingleObject(&SleepTimer, UserRequest, KernelMode, FALSE, NULL);
return;
}
TDI_ADDRESS_IPX UNALIGNED *
SpxParseTdiAddress(
IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress
)
/*++
Routine Description:
This routine scans a TRANSPORT_ADDRESS, looking for an address
of type TDI_ADDRESS_TYPE_IPX.
Arguments:
Transport - The generic TDI address.
Return Value:
A pointer to the IPX address, or NULL if none is found.
--*/
{
TA_ADDRESS * addressName;
INT i;
addressName = &TransportAddress->Address[0];
// The name can be passed with multiple entries; we'll take and use only
// the IPX one.
for (i=0;i<TransportAddress->TAAddressCount;i++)
{
if (addressName->AddressType == TDI_ADDRESS_TYPE_IPX)
{
if (addressName->AddressLength >= sizeof(TDI_ADDRESS_IPX))
{
return ((TDI_ADDRESS_IPX UNALIGNED *)(addressName->Address));
}
}
addressName = (TA_ADDRESS *)(addressName->Address +
addressName->AddressLength);
}
return NULL;
} // SpxParseTdiAddress
BOOLEAN
SpxValidateTdiAddress(
IN TRANSPORT_ADDRESS UNALIGNED * TransportAddress,
IN ULONG TransportAddressLength
)
/*++
Routine Description:
This routine scans a TRANSPORT_ADDRESS, verifying that the
components of the address do not extend past the specified
length.
Arguments:
TransportAddress - The generic TDI address.
TransportAddressLength - The specific length of TransportAddress.
Return Value:
TRUE if the address is valid, FALSE otherwise.
--*/
{
PUCHAR AddressEnd = ((PUCHAR)TransportAddress) + TransportAddressLength;
TA_ADDRESS * addressName;
INT i;
if (TransportAddressLength < sizeof(TransportAddress->TAAddressCount))
{
DBGPRINT(TDI, ERR,
("SpxValidateTdiAddress: runt address\n"));
return FALSE;
}
addressName = &TransportAddress->Address[0];
for (i=0;i<TransportAddress->TAAddressCount;i++)
{
if (addressName->Address > AddressEnd)
{
DBGPRINT(TDI, ERR,
("SpxValidateTdiAddress: address too short\n"));
return FALSE;
}
addressName = (TA_ADDRESS *)(addressName->Address +
addressName->AddressLength);
}
if ((PUCHAR)addressName > AddressEnd)
{
DBGPRINT(TDI, ERR,
("SpxValidateTdiAddress: address too short\n"));
return FALSE;
}
return TRUE;
} // SpxValidateTdiAddress
ULONG
SpxBuildTdiAddress(
IN PVOID AddressBuffer,
IN ULONG AddressBufferLength,
IN UCHAR Network[4],
IN UCHAR Node[6],
IN USHORT Socket
)
/*++
Routine Description:
This routine fills in a TRANSPORT_ADDRESS in the specified
buffer, given the socket, network and node. It will write
less than the full address if the buffer is too short.
Arguments:
AddressBuffer - The buffer that will hold the address.
AddressBufferLength - The length of the buffer.
Network - The network number.
Node - The node address.
Socket - The socket.
Return Value:
The number of bytes written into AddressBuffer.
--*/
{
TA_IPX_ADDRESS UNALIGNED * SpxAddress;
TA_IPX_ADDRESS TempAddress;
if (AddressBufferLength >= sizeof(TA_IPX_ADDRESS))
{
SpxAddress = (TA_IPX_ADDRESS UNALIGNED *)AddressBuffer;
}
else
{
SpxAddress = (TA_IPX_ADDRESS UNALIGNED *)&TempAddress;
}
SpxAddress->TAAddressCount = 1;
SpxAddress->Address[0].AddressLength = sizeof(TDI_ADDRESS_IPX);
SpxAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IPX;
SpxAddress->Address[0].Address[0].NetworkAddress = *(UNALIGNED LONG *)Network;
SpxAddress->Address[0].Address[0].Socket = Socket;
RtlCopyMemory(SpxAddress->Address[0].Address[0].NodeAddress, Node, 6);
if (AddressBufferLength >= sizeof(TA_IPX_ADDRESS))
{
return sizeof(TA_IPX_ADDRESS);
}
else
{
RtlCopyMemory(AddressBuffer, &TempAddress, AddressBufferLength);
return AddressBufferLength;
}
} // SpxBuildTdiAddress
VOID
SpxBuildTdiAddressFromIpxAddr(
IN PVOID AddressBuffer,
IN PBYTE pIpxAddr
)
{
TA_IPX_ADDRESS UNALIGNED * SpxAddress;
SpxAddress = (TA_IPX_ADDRESS UNALIGNED *)AddressBuffer;
SpxAddress->TAAddressCount = 1;
SpxAddress->Address[0].AddressLength = sizeof(TDI_ADDRESS_IPX);
SpxAddress->Address[0].AddressType = TDI_ADDRESS_TYPE_IPX;
SpxAddress->Address[0].Address[0].NetworkAddress = *(UNALIGNED LONG *)pIpxAddr;
RtlCopyMemory(
SpxAddress->Address[0].Address[0].NodeAddress,
pIpxAddr+4,
6);
GETSHORT2SHORT(
&SpxAddress->Address[0].Address[0].Socket,
pIpxAddr + 10);
return;
}
VOID
SpxCalculateNewT1(
IN struct _SPX_CONN_FILE * pSpxConnFile,
IN int NewT1
)
/*++
Routine Description:
Arguments:
NewT1 - New value for the RTT in ms.
Return Value:
--*/
{
int baseT1, error;
//
// VAN JACOBSEN Algorithm. From Internetworking with Tcp/ip
// (Comer) book.
//
error = NewT1 - (pSpxConnFile->scf_AveT1 >> 3);
pSpxConnFile->scf_AveT1 += error;
if (pSpxConnFile->scf_AveT1 <= 0) // Make sure not too small
{
pSpxConnFile->scf_AveT1 = SPX_T1_MIN;
}
if (error < 0)
error = -error;
error -= (pSpxConnFile->scf_DevT1 >> 2);
pSpxConnFile->scf_DevT1 += error;
if (pSpxConnFile->scf_DevT1 <= 0)
pSpxConnFile->scf_DevT1 = 1;
baseT1 = (((pSpxConnFile->scf_AveT1 >> 2) + pSpxConnFile->scf_DevT1) >> 1);
// If less then min - set it
if (baseT1 < SPX_T1_MIN)
baseT1 = SPX_T1_MIN;
// Set the new value
DBGPRINT(TDI, DBG,
("SpxCalculateNewT1: Old value %lx New %lx\n",
pSpxConnFile->scf_BaseT1, baseT1));
pSpxConnFile->scf_BaseT1 = baseT1;
// At the time of restarting the timer,we convert this to a tick value.
return;
}